セカンドライフでプログラム2(座標の話とその変換の話)

セカンドライフ制作
スポンサーリンク

こんにちは。

いつもながら、セカンドライフのプログラム勉強してます!
今回は、世界(リージョン)と座標について話します!

世界は複数のリージョンから成り立っています。
このリージョンは1つごとに、SIMプロセス1つで計算しているようです。

map
ミニマップをみると、こんな感じで、明るい場所が1リージョンとなっています。
隣のリージョンがあれば、陸続きで移動することもできます。
黄色いところが現在位置です。緑が他人位置です。
下矢印で自分より下の座標に、上矢印で自分より上の座標にいることになります。
1リージョンあたりは、256m x 256m となっています。
このリージョン内でいろいろなことができます。

position
ちなみに、現在位置の座標はこんな感じです。
これを見るとわかるとおり、
東西がX軸南北がY軸上下の高さがZ軸になっています。
東がX座標+、西がX座標ー
北がY座標+、南がY座標ー

position_box
試しに、オブジェクトを、このリージョン内に設置してみたところです。
軸の色からも、赤色がX軸緑色がY軸青色がZ軸ということが分かると思います。

rot_2
ちなみに回転させるとこんな感じになります。
上の図ではY軸周りですでに-85度回転させたものです。

rot
回転させると、こんな感じの表示になります。
Y軸の箇所が275度になっています。
これを見るとわかるように、軸に対して時計回りが+、反時計周りがーとなっています。

3Dの専門用語で表すと、
X → ピッチ
Y → ロール(バンク)
Z → ヨー
となっています。

これまでで話したのはリージョンの座標空間であり、
リージョンに直接物を置いた場合は、上記のリージョン座標で考えればいいので単純です。
※回転の話については、この物体内のローカル座標空間となっています。

ただ、この座標空間というのは、実際にはいろいろな座標空間が存在しており、
自分の座標空間でのみしか影響させない場合など、座標空間を変えない場合も問題は特に出てこないのですが、
座標空間を変える場合となると、複雑になってきます。

また、この物体をプリムと呼ぶのですが、複数のプリムを1つとして扱うことができます。
この場合も座標空間のことを考えないと、うまくプログラムできない場合があります。

プリムをリンクした時の座標の話は、ここでは割愛します。
今回は、プリムをアバターが装備した時のプリムの位置と、リージョン座標との関係の話をします。
とくに、プリムを装備した時に、そのプリムの位置をリージョン座標でいうと、
どの座標なのかを調べる方法です。

secondlife_region_local
ちょっと汚い画像ですが、プリムを背骨に付けた時の図です。
この画像から分かるように、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);
}

コメント

タイトルとURLをコピーしました