こんにちは。
いつもながら、セカンドライフのプログラム勉強してます!
今回は、世界(リージョン)と座標について話します!
世界は複数のリージョンから成り立っています。
このリージョンは1つごとに、SIMプロセス1つで計算しているようです。
ミニマップをみると、こんな感じで、明るい場所が1リージョンとなっています。
隣のリージョンがあれば、陸続きで移動することもできます。
黄色いところが現在位置です。緑が他人位置です。
下矢印で自分より下の座標に、上矢印で自分より上の座標にいることになります。
1リージョンあたりは、256m x 256m となっています。
このリージョン内でいろいろなことができます。
ちなみに、現在位置の座標はこんな感じです。
これを見るとわかるとおり、
東西がX軸、南北がY軸、上下の高さがZ軸になっています。
東がX座標+、西がX座標ー
北がY座標+、南がY座標ー
試しに、オブジェクトを、このリージョン内に設置してみたところです。
軸の色からも、赤色がX軸、緑色がY軸、青色がZ軸ということが分かると思います。
ちなみに回転させるとこんな感じになります。
上の図ではY軸周りですでに-85度回転させたものです。
回転させると、こんな感じの表示になります。
Y軸の箇所が275度になっています。
これを見るとわかるように、軸に対して時計回りが+、反時計周りがーとなっています。
3Dの専門用語で表すと、
X → ピッチ
Y → ロール(バンク)
Z → ヨー
となっています。
これまでで話したのはリージョンの座標空間であり、
リージョンに直接物を置いた場合は、上記のリージョン座標で考えればいいので単純です。
※回転の話については、この物体内のローカル座標空間となっています。
ただ、この座標空間というのは、実際にはいろいろな座標空間が存在しており、
自分の座標空間でのみしか影響させない場合など、座標空間を変えない場合も問題は特に出てこないのですが、
座標空間を変える場合となると、複雑になってきます。
また、この物体をプリムと呼ぶのですが、複数のプリムを1つとして扱うことができます。
この場合も座標空間のことを考えないと、うまくプログラムできない場合があります。
プリムをリンクした時の座標の話は、ここでは割愛します。
今回は、プリムをアバターが装備した時のプリムの位置と、リージョン座標との関係の話をします。
とくに、プリムを装備した時に、そのプリムの位置をリージョン座標でいうと、
どの座標なのかを調べる方法です。
ちょっと汚い画像ですが、プリムを背骨に付けた時の図です。
この画像から分かるように、3つ座標の変換が行われていると思います。
(1)リージョン座標で、アバターまでの位置を表します。
(2)アバターの中心点から、背骨の装着位置までの座標へ
(3)背骨の座標から装着したプリムまでの座標です
で、これからわかるとおり、座標変換を何回か行う必要があると思いますが、
この中で(2)を取得する方法は調べた限り恐らくありません。
取れない理由の予想として、この(2)の座標はアバターの動き(ボーン)によるものだからです。
アバターのモーションは、他のパソコンとか、実行環境とで同期をとっているわけではないため、
この座標を取得しても意味はないと思われるためです。
では、(2)はどうするかというと、どうしようもないので、距離に関しては無視しましょう。
アバターの位置から背骨までの距離は近いはずですから。
ただ、回転については考慮する必要はあります。
それでは、それぞれの座標位置、回転についての取得方法の解説です。
(1)
リージョン座標の中で、アバターの中心座標へはllGetRootPositionで取得できます。
そして、アバターの座標空間上では、アバターの回転角度は、llGetRootRotationで取得できます。
といいたいのですが、なぜか、Z軸で回転しているようで、(アバター、モーションによる?)
llEuler2Rot( <0, 0, -90> * DEG_TO_RAD ) * llGetRootRotation();
で正しく回転角度がとれます。
なお、掛け算しているのは、回転を合成するためです。
合成の順番が回転の順番と対応していまして、計算が変わってきますので注意。
(2)
アバターの中心座標から、装着位置の座標までは、先ほど言ったように取得方法が分かりません。
座標は近いのでまあ問題ないとしても、回転角度は必ず必要です。
とりあえず、自分で2つだけ調べてみました。
これも使用するアバター、モーションによると思います。
・装着位置が「背骨」
llEuler2Rot( <-90, 180, 0> * DEG_TO_RAD );
・装着位置が「アバターの中央」
llEuler2Rot( <0, 0, -90> * DEG_TO_RAD );
(3)
位置を調べるのは簡単です。
llGetLocalPos()
これから分かるように
リージョン座標からローカル座標を知るためには、(1)→(2)の計算が必要です。
※(3)はすでにあるローカル座標位置なのでここでは関係なし。
ローカル座標からリージョン座標を知るためには、(3)→(2)→(1)という順番で計算します。
まとめて、関数をかくとこんな感じです。
変換するときは、移動や回転を反対の順番で演算しているのがポイントです。
vector getResionPosition() { vector pos; rotation rotCalibration; integer attach_point = llGetAttached(); // 装着時の補正 // 背骨 if(attach_point == ATTACH_BACK) { rotCalibration = llEuler2Rot( <-90, 180, 0> * DEG_TO_RAD ); } // アバターの中央 else if(attach_point == ATTACH_AVATAR_CENTER) { rotCalibration = llEuler2Rot( <0, 0, -90> * DEG_TO_RAD ); } else { rotCalibration = <0, 0, 0, 1>; } pos = llGetLocalPos(); // ルートからの座標 pos /= rotCalibration; // 装着箇所による補正 pos /= llGetRootRotation(); // アバターの回転分だけ戻す pos /= llEuler2Rot( <0, 0, -90> * DEG_TO_RAD ); // ルートローテーションの補正 pos += llGetRootPosition(); // アバターのリージョン座標を足して補正 return(pos); } vector toRootPositionByResionPosition(vector pos) { rotation rotCalibration; integer attach_point = llGetAttached(); // 装着時の補正 // 背骨 if(attach_point == ATTACH_BACK) { rotCalibration = llEuler2Rot( <-90, 180, 0> * DEG_TO_RAD ); } // アバターの中央 else if(attach_point == ATTACH_AVATAR_CENTER) { rotCalibration = llEuler2Rot( <0, 0, -90> * DEG_TO_RAD ); } else { rotCalibration = <0, 0, 0, 1>; } pos -= llGetRootPosition(); // アバターのリージョン座標補正 pos *= llEuler2Rot( <0, 0, -90> * DEG_TO_RAD ); // ルートローテーションの補正 pos *= llGetRootRotation(); // アバターの回転 pos *= rotCalibration; // 装着箇所による補正 return(pos); }
コメント