大抵のエディターの場合 回転が DEG値で<x,y,z>となっている場合
これをオイラー角とか呼称します
んでなんでこれが3dプログラミングだとまずいかってーと
"ジンバルロック"
っチュー現象がどうやったっておきます
大雑把に説明すると基準平面に対して自分の現在の向きから
行える方向転換が限定される現象のことです
んでまぁ タイトルにあるような演算が必要な用途として
例えば飛行機ゲーム あとはFPS
ここ最近の航空機のグラスコックピットの場合
このオイラー角を直感的にわかるようにした計器がついてます
んで X軸を正面 Y軸を側面 Z軸を上面とした場合に
x軸:ロール
y軸:ピッチ
z軸:ヨー
って感じで記述することが可能
ゲームでの航法や射撃ならピッチとヨーだけわかってりゃ
とりあえず自分が向きたい方向を表現できる
けど基準平面が無い空間だったり姿勢まで見るならロールも欲しい ッて感じだな
んで大抵の3Dプログラミングだと
回転値はクオータニオンっちゅー4値あるデータを使います
理由は
"ジンバルロック"の対策ね
んでまぁ大抵のSDKの場合 クオータニオンとオイラー角は
相互変換のライブラリーが揃ってます
ただこの相互変換関数
望む結果が出ることはほぼありません
何故か
変換時にZYXの順番で処理するから
(直感的に回しやすいのは大抵XYZの順番なので)
そこはライブラリーというか使い方があります
オイラー角のXYZを個別のクオータニオンとして生成して合成すればいい
逆もしかり
具体的な計算式は
オイラー角からクオータニオンへの変換
目的の回転rot=(X回転のeuler2rot)*(Y回転のeuler2rot)*(Z回転のeuler2rot)
クオータニオンからオイラー角への変換は
回転z=クオータニオンのローカルX軸のvectorのyとxでAtan2
回転y=クオータニオンのローカルX軸のvectorのzとxy合成した長さでAtan2
面倒なのでLSL表記すると
行える方向転換が限定される現象のことです
んでまぁ タイトルにあるような演算が必要な用途として
例えば飛行機ゲーム あとはFPS
ここ最近の航空機のグラスコックピットの場合
このオイラー角を直感的にわかるようにした計器がついてます
んで X軸を正面 Y軸を側面 Z軸を上面とした場合に
x軸:ロール
y軸:ピッチ
z軸:ヨー
って感じで記述することが可能
ゲームでの航法や射撃ならピッチとヨーだけわかってりゃ
とりあえず自分が向きたい方向を表現できる
けど基準平面が無い空間だったり姿勢まで見るならロールも欲しい ッて感じだな
んで大抵の3Dプログラミングだと
回転値はクオータニオンっちゅー4値あるデータを使います
理由は
"ジンバルロック"の対策ね
んでまぁ大抵のSDKの場合 クオータニオンとオイラー角は
相互変換のライブラリーが揃ってます
ただこの相互変換関数
望む結果が出ることはほぼありません
何故か
変換時にZYXの順番で処理するから
(直感的に回しやすいのは大抵XYZの順番なので)
じゃぁ使い物にならねーじゃねーかってなるわけですが
そこはライブラリーというか使い方があります
オイラー角のXYZを個別のクオータニオンとして生成して合成すればいい
逆もしかり
具体的な計算式は
オイラー角からクオータニオンへの変換
目的の回転rot=(X回転のeuler2rot)*(Y回転のeuler2rot)*(Z回転のeuler2rot)
クオータニオンからオイラー角への変換は
回転z=クオータニオンのローカルX軸のvectorのyとxでAtan2
回転y=クオータニオンのローカルX軸のvectorのzとxy合成した長さでAtan2
回転y=クオータニオンからzy回転を引いたローカルy軸のvectorのzとyでAtan2
面倒なのでLSL表記すると
vector rot2angle(rotation rot){
vector vec=<1,0,0>*rot;
vector angle;
angle.z=llAtan2(vec.y,vec.x);
angle.y=-llAtan2(vec.z,llVecMag(<vec.x,vec.y,0>));//yだけatan2と逆回りになる
rot= rot /llEuler2Rot(<0,0,angle.z>)/llEuler2Rot(<0,angle.y,0>);
vec=<0,1,0>*rot;
angle.x=llAtan2(vec.z,vec.y);
return angle;
}
rotation angle2rot(vector angle){
rotation rot=llEuler2Rot(<angle.x,0,0>)*llEuler2Rot(<0,angle.y,0>)*llEuler2Rot(<0,0,angle.z>);
return rot;
}
default
{
touch_start(integer total_number)
{
llSay(0, (string)(rot2angle(llGetRot())*RAD_TO_DEG));
llSay(0, (string)(angle2rot(rot2angle(llGetRot())))+","+(string)llGetRot());
}
}
大体こんな感じ
出力(サンプル)
[11:36] Object: <44.99883, -45.00175, -44.99999>
[11:36] Object: <0.19133, -0.46195, -0.19134, 0.84462>,<0.19133, -0.46195, -0.19134, 0.84462>
ってなところかね
以上