2014年11月6日木曜日

rotationからオイラー角(ピッチ ロール ヨー)を取り出す方法

基本的な考え方として

大抵のエディターの場合 回転が 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

回転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>


ってなところかね

以上

2014年11月5日水曜日

チャットが聞こえる範囲と邪魔なメッセージをスマートに絞る方法

ヴィークルとかで乗ってるアバターにだけ聞こえる状態にしたいけど
○○のささやき とか出るのはダサいとか
ラップタイマーとかでログを整理したいときに
○○の叫び とか出るのはちょいと面倒だとか

その辺をスマートに解決する方法

やりかた自体はちょー簡単で
Stringの先頭に "/me :"
これを追加するだけ

以下がサンプル

default
{
    touch_start(integer total_number)
    {
        llSay(0, "/me :Say.");
        llWhisper(0, "/me :Whisper.");
        llShout(0, "/me :Shout.");
    }
}

ってなところかね

以上