Adsense

2010年10月10日日曜日

[LSL] 位置と回転について ~ 基準はどこにあるの? ~

前回では移動量(クォータニオン)と高さを使えば空間のあらゆる位置を表現できる、という方法を説明してみました。ただし、その場合でもある地点を「基準」として考えたら、、、という前提があったことを思い出してください。

この基準、、、というのが難しいのです。

3. 基準はどこにあるの?

地球上の位置を考えたとき、よく例にでるのがイギリスにあるグリニッジ天文台の子午線ですが、前回ではそれに赤道も加え、経度0度の子午線と緯度0度の赤道の交点がギニア湾上にある、ということを紹介しました。その位置は「緯度0度、経度0度」の位置です。

そして、その位置は地球の中心から見て「地球の半径」の高さ(あえていえば、海抜 0 m もしくは標高 0 m)を加えることで「ピンポイント」で地球の表面上の位置の特定が可能になります。

そして以下の絵でご説明したように、回転であらわした「移動量」が同じでも、地球の半径に相当する R の距離(もしくは高さ)を変えることで違う位置をさすことが可能だということも理解できたと思います。

rotation

Secondlife のインワールドで移動量と半径Rで空間内のすべての位置を表現するには、考えなくてはならない「基準」が球体の中心 <0.0,0.0,0.0> だけではないのがミソなんです。

地球でいう緯度0度、経度0度、標高 0m の地点はどこにあるのでしょうか。

これ、、、実は明確には無いのです。(今のわたしの理解では^^;)

複数の SIM からなる SecondLife なので、他の SIM をぜーんぶひっくるめて「地球」のような感覚になりがちですが、位置の特定にかぎっていえば 1 つの SIM がすべてです。この1つの SIM で、球体の中心を <0.0, 0.0, 0.0> におき、さらに、LSL で扱いやすくするために、地球上のギニア湾上にある緯度0度、経度0度、標高0m(地球の半径)のような「基準」をグローバル座標で以下の地点だと「仮定」します。

<1.0, 0.0, 0.0>

上の絵で、<0.0, 0.0, 0.0> の球体の中心点からグローバル座標の X 軸上で 1m いった地点。これを緯度0度、経度0度、標高0m と同じように扱ってみるのです。ここが絵でいうピンクの線の基準。

ええ、、、でも、たとえば自分が <100.0, 82.0, 36.0> のグローバル座標の位置にいて、それで <1.0, 0.0, 0.0> の基準点(もしくは基準ベクトル)をつかって何がわかるの?となりますよね。ただ、もう一度思い出してください。同心円(もしくは同じ球面)にいなくても、移動量(クォータニオン)は 上の図でいえば A1, A2, A3 は同じ、B1, B2, B3 も同じ、、、ということを。そうすると、半径 1.0 m の球面上で、上の絵の中の線で言えば赤い直線、青い直線上の地点への移動量がわかれば、あとはどれだけ中心から離れているかの組み合わせで、<100.0, 82.0, 36.0> の地点を示すのと同じことができるのです。

そのための便利な関数が llRotBetween() なのです。

wiki の説明では llRotBetween の引数には単位ベクトル的な数値(x や y や z が 1.0) しか入れていませんが、この関数が本領発揮してくれるのは単位ベクトル以外のベクトルをいれても、2つの位置間の「移動量」を計算してくれるのです。

上の絵でいうと、A2 と B3 の間の移動量を出してくれる、ということです。同心円上の A2 と B2 の移動量も、同心円上にない A2 と B3 の移動量は同じことはもう理解できますよね。違うのは中心からの距離、半径 R なのです。

なので、グローバル座標上の <100.0, 82.0, 36.0> を移動量(クォータニオン)と <0.0,0.0,0.0> からの距離で表すと

移動量(クォータニオン)r は、
rotation r = llRotBetween(<1.0, 0.0, 0.0>,<100.0,82.0,36.0>);

<0.0, 0.0, 0.0>から<100.0, 82.0, 36.0>までの距離は
float d = llVecMag(<100.0, 82.0, 36.0>);
または
float d = llVecDist(<0.0,0.0,0.0>,<100.0,82.0,36.0>);

となります。この r と d でグローバル座標上の位置の計算は以下で可能です。

vector v = llRot2Fwd(r)*d; //注1) なぜ llRot2Fwd か理解できない人は最後の(注1)を参照してみてください。

これで、v の値は自分の位置の <100.0, 82.0, 36.0> になるのです。

この基準の考え方を応用すると、リンクされた子プリムのルートプリムからの相対位置を計算することができます。ルートに対する相対とは「ルートから見て(ルートを中心として)」どのくらい差分があるか、ということで、特に llSetLinkPrimitiveParams() で子プリムの位置や傾きを設定する PRIM_POSITION や PRIM_ROTATION で使用できます。子プリムがルートからみてどの位置にあるか、どんな傾きになっているかを算出してはじめて llSetLinkPrimitiveParams が使えるようになるわけです。そのときルートプリムは自分が傾いているなんて考えていません。また自分がグローバル座標のどの位置にいても、「自分からみてどのくらいの距離にいるか、自分から見て前後・左右・上下のどのくらいの位置にいるか」が重要となります。

次はここまでの知識を元にルートプリムと子プリムの関係について考えてみたいと思います。

(注1)llRot2Fwd を使ったのは、基準となる位置(ベクトル)を <1.0, 0.0, 0.0> と仮定したためです。X 軸は東西であると同時に前後になります。<0.0, 0.0, 0.0> から前に1歩進んだ状態で、移動量によってくるりと回転した状態からさらにベクトルを伸ばそうとするので前に進む、なので llRot2Fwd を使います。

もし基準となる位置(ベクトル)を <0.0,1.0,0.0> としたら、<0.0,0.0,0.0>から左に一歩分横に移動したようなものです。この状態で移動量分くるりとまわし、ベクトルを伸ばそうとすると、今度は llRot2Fwd ではなく llRot2Left を使って左に進むことでベクトル算出をすることになります。