Adsense

2008年11月19日水曜日

位置と回転を理解したい その2

前回からの続きです。

llSetPosllGetPos を使った 西へ1m, 南へ2m, 上に1m の指定方法は理解できました。
次に、「前に1m, 左に2m, 上に1m」という設定をするには、オブジェクトが向いている方向、つまり「回転」を理解しなくてはなりませんでした。「回転」っていうとクルクルまわっているイメージを持ってしまいますが、どっちを向いているかの「方向」だと置き換えて考える必要がありました。

実は、、プリムの正面っていうのは決まっています。立方体にすると第2面が「顔」になります。(笑
西(W) を向いている方向です。 Rez したときの、東西の矢印の方向です。

0

地図上の東西が X 軸、南北が Y 軸、上下が Z 軸で、それをグローバル座標軸とよびます。グローバル座標軸はどこにいても、どちらを向いていても変わることはありません。一方、前後、左右、上下(ええ、上下も自分が傾いていたら上下軸も傾きますね)はそのときの状態でかわります。この前後、左右、上下を表す軸をローカル座標軸と呼びます。(便宜上、それぞれの軸をグローバル座標軸と同じように、ローカル座標軸の X, Y, Z と呼ばれます。また、この X, Y, Z は右手座標系と呼ばれるものに基づいていて、左手座標系の場合は X, Z, Y となります。他の回転・旋回の記事を参照するときは注意が必要です。。。)

プリムを作成したときはグローバル座標軸とローカル座標軸は一致していますが、プリムが回転してしまったら、グローバル座標軸とローカル座標軸は違うものになりますね。

1

前後に移動する、というのは東西、南北のグローバル座標軸を使うより、ローカル座標軸の X 軸に沿って移動する、左右に移動するというのはローカル座標軸の Y 軸に沿って移動する、と考えれば簡単そうですよね。

llGetRot を使って向いている方向を取得する

向いている方向、つまり、回転を扱うときに私がつまずいたのがローテーション型 (rotation) というものです。現在の回転の値を取得する llGetRot によって返される値は rotation 型と呼ばれる型の値で、ベクトル(ベクター)型とは違います。クォータニオン (quaternion) とも呼ばれるこの型の説明をネット上で探すと、、、<x, y, z, s> の4つの要素からなる4元数で、ジンバルロックが、三角関数が、虚数が(!)、、、と情報は豊富なのですが、数学をちゃんとやっていないと馴染みの薄い難しい単語が続きます。これをひとつひとつ理解しようとすると、かなり大変です。(それはそれで面白いのですけどね。。。)
ですので、x, y, z, s の4つの数字が意味することにあまり深く入らなくてもいいと思います。
実際、rotation 型に入る 4つの数値を直接いじることは私のやりたい範囲では皆無でした。
とりえあず、、、llGetRot で現在の向いている方向が rotation 型で表現できる、と理解して先に進みます。
(あとで、、、角度とローテーションの関係でもう一度でてくることになります)
(なお、wiki.secondlife.com の回転(ローテーション)についての日本語の記事がこちらになります。)

本題に戻って、llGetRot で今向いている方向がとれたら、次は「前」ですよね。LSL では「前」に進むための移動距離をとる関数が用意されていて、それが llRot2Fwd になります。
これが、、、「位置」と「回転」が違うことを意識していないとごちゃごちゃになる壁かもしれません。
いま、llGetRot() で「どの位置か」は関係なく、向いている方向を表す rotation 型の数値を取得できました。向いている方向がわかったらローカル座標軸にそった前方 1m の位置の情報をとりたい、ということですよね。最終的に llSetPos を使って位置を設定したいなら <x, y, z> のグローバル座標軸の位置情報がほしくなります。
そこで llRot2Fwd を使います。llRot2Fwd に現在の向きの情報を llGetRot() で取得して渡すと、Unit Vector (単位ベクトル)という値を返します。

vector fwdVec = llRot2Fwd(llGetRot());

<x, y, z> のベクトル型のデータを fwdVec にもらっていますが、これは「位置」をあらわす <x, y, z> ではありません。
Unit Vector (単位ベクトル) と呼ばれているのは現在の位置からローカル座標軸に沿って 1m 前に進むための「グローバル座標軸上の」移動方向を表しているのです。今のところから「前に 1m 進む」には東へ Xm、北へ Ym、上に Zm いきなさい、ということです。
最初この llRot2Fwd を知らなくて、三角関数の llSin, llCos を使って 1m 先に進むためのグローバル座標軸の値を算出しようとしていたんです、、、。
ええ、直角三角形の1辺が 1m になるような X 軸と Y 軸の値を、、、もう、十何年ぶりにピタゴラスの定理です(笑
2
これ、常に地面に垂直にいればいいですが、傾いた時点でかなり面倒なことになりそうなのは理解していました。こんなめんどうなことやらないかも、と思い検索してたら llRot2Fwd を運よく見つけたのでした。
繰り返しになりますが、ローカル座標軸の 前後、左右、上下方向に 1m 進むために、グローバル座標軸上の 東西、南北、天地 での進まなくてはならない移動距離を出してくれるのが、llRot2Fwd, llRot2Left, llRot2Up という便利な関数になるわけです。
そうすると、

1) 現在の向きをllGetRot でとって
2) llRot2Fwd(llGetRot()) と渡して、向いている方向に 1m 進むための東西・南北・天地の値を算出し、
3) 現在の位置を llGetPos でとり、そこに 2) で算出した値を足し、
4) 今の位置から前方 1m のグローバル座標軸上の位置を llSetPos に渡すことができる、

ということですね。 2m 進みたかったら llRot2Fwd を2倍すればよいですし、後方ならば -1 をかければよい、ということです。
これで思い通りの場所にオブジェクトを移動させたり、Rez したりできるようになりそうでした。
が、、、、
今度は Rez したオブジェクトを「右へ90度向かせる」、「反対方向(180度)に向かせる」などの調整をしたくなりました。
ここではじめて「とりあえずこんなもの」と理解していたローテーション型(クォータニオン)の「すごさ」を実感することになりました。
つづく・・・