Adsense

2008年11月25日火曜日

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

「その2」からのつづきで、、、これが「ネジ」です(笑

0

このネジに座ることで Sit の Animation をストップし、ネジ自身を透明にして、ダンスを踊る位置決めをしたかったのです。
前回プリムの正面のお話しを書きましたが、このネジの先端が「正面」になります。
正面の向きは常に西をみているわけではありません。クラブやステージなどによっては当然違います。

このネジを整列させながら Rez して、、、というのもスクリプトでやるのですが、Rez された複数のネジをたとえば 45度時計まわりに回転させたいとか、180度逆向きにさせたい、というのをプリムの編集からまわすのではなく、ダイアログのボタンで簡単にどんどん行いたい、と思ったわけです。

いつものごとく、「そんなの知ってるよ~」の人はスルーしてください(笑

クォータニオンは右からなのか左からなのかそれがポイント

rotation (ローテーション)型のクォータニオンについては「そんなもの~でとりあえず理解しましょう」と前回ご紹介しましたが、クォータニオンがすごい!と思ったのは、このシリーズ(?)で何度もでてくる「グローバル座標軸」(東西、南北、天地)と「ローカル座標軸」(前後、左右、上下)の双方を簡単に扱えることでした。

回転(というより「向き・方向」ですね)を指定する方法も、位置を指定するとき同様にグローバル座標をもとに向きを設定するのか、ローカル座標をもとに向きを設定するのかを考慮しなくてはなりません、、、といっても私も最初はピンとこなかった。。。(笑

まずは「軸を中心とした回転」を考えてみます。
これはプリムの [編集] の [回転] の数字をいじるのと同じことです。
このとき回転する方向はセカンドライフは右手座標系なので「右手の法則」(右ねじの法則)を使います。詳しいことは多くの方が記事にされているのでそちらを参考にしてもらって、、、、これも、見る方向で「時計まわり」なのか「反時計まわり」なのか変わるので注意が必要です。回転させる軸のグローバル座標軸の矢印と同じ方向をみて「時計まわり」になります。
これ、、、混乱するんですよね~

天地の軸である Z 軸を例にとると、おおよそプリムを Rez すると図のような状態で回転を試すことになります。
Z 軸を使って45度 [編集] - [回転] で回してみると、、、反時計まわりにまわっているようにみえますよね。
1
この図をよくみてみると天地の軸である Z 軸は上の方に向かって矢印があります。上記で赤で「回転させる軸のグローバル座標軸の矢印と同じ方向を見る、、、」としたのは、、、つまり、この図の場合は地中からプリムを見上げて時計まわり、ということになるからです。

これは慣れていくしかありませんね。

Z 軸で 45度回したいをベクトルで書こうとすると <0.0, 0.0, 45.0> と書きたくなりますし、[編集] - [回転] でも 45.0 という数値を使いますが、スクリプトではこの角度をラジアンというものにしないと使えません。このあたりの Degree(度) と Radian(ラジアン) の説明もいろいろなところに詳しくあるのでそちらを参照してもらうことにして、LSL で 度からラジアンに変更する方法があるのでそれだけを覚えてしまいます。

<0.0, 0.0, 45.0> * DEG_TO_RAD

これで Z軸45度がラジアンの形にかわります。ラジアンから度に変更するには RAD_TO_DEG という定数をかけてあげればいいのです。

ただ、これだけでは済まないのが回転の難しいところです。
現在の回転(向き)を表す rotation 型の値は llGetRot() でとることができました。
この現在の向きに Z軸を中心とし45度まわった後の「向き」の値を、今度は向きを設定する関数の llSetRot に渡せばよい、、、ということになりますね。
そのため llEuler2Rot という関数を使って <0.0, 0.0, 45.0> のベクトル型の値をラジアンにしてから <x, y, x, s> のローテーション型に変換してあげます。

rotation q = llEuler2Rot(<0.0, 0.0, 45.0>*DEG_TO_RAD);

これで返された q というローテーション型の値を現在の位置に、、、、積算します。加算するのではなくてかけるのです。

rotation newRot = llGetRot()*q;

この newRot は現在の向きからグローバル座標軸の z を中心に 45度 まわしたあとの向きになります。よって、

llSetRot(newRot);

で、向きを変更できました。

クォータニオンがすごいのは、、、上記の例はグローバル座標軸もローカル座標軸も重なっている場合ですが、たとえば図のように傾いていた場合で、プリムの上下軸(つまり傾いているローカル座標軸)を中心に同じく45度まわしたい場合は、

rotation newRot = q * llGetRot();

と、今度は q を左からかけてあげるだけでローカル座標軸を中心とした回転後の向きを算出できるからです。
2
余談ですが、このローカル座標の前後、左右、上下の軸をピッチ (picth)、ロール (roll) 、ヨー (yaw) と呼ぶそうです。(注1)
クォータニオンすごすぎ・・・(笑

ちなみに、、回転する量を <30.0, 45,0, 20,0> と指定した場合、X, Y, Z の順番ではなく、Z軸で20度、Y軸で45度、X軸で30度という順番で回転した結果を表すことに注意です。位置の指定と違って回転の場合はこの順番で結果の向きが変わります。
これで「ネジ」の場合はおおよそやりたいことができるようになったのですが、、、今度は「向きを指定する」といっても角度がわからないときもあるわけ、、、ですよね。
たとえば、近くのアバターの方向を向くとか、太陽の方向を向くとか、、そういう指定もありえます。

だんだん、ネジから離れていくのですが(笑 木漏れ日、太陽光、月光を表現しているプリムも何度も見たことがあるのでちょっと調べようと思ったのですが、、、これがまた(笑
つづく・・・

追記(注1)
誤解がありそうな表現なので、、、ピッチ(前後)の角度、つまり飛行機に乗った状態を想像して、上方に向かったり、下方に向かったりするのは「ピッチ角」を変える、というようですが、軸中心で考えると、ローカル座標軸のY軸をまわしています。同じようにロール(左右)は X 軸を回転させて角度を変えることで右に傾いたり、左に傾いたりします。ピッチの軸が前後のX軸ではないんですよね。