Rotation/ja
LSL ポータル | 関数 | イベント | 型 | 演算子 | 定数 | 実行制御 | スクリプトライブラリ | カテゴリ別スクリプトライブラリ | チュートリアル |
Rotation
LSL のrotation型は3Dでの方位を表すのに用いられます。(型名を太字で書くように心がけています。)方位あるいは3Dアングルは四元数と呼ばれる数学的オブジェクトによって表されます。四元数は4つの数値から成ると考えることができ、3つがオブジェクトの向いている方向を表し、4つめがその方向の周りでのオブジェクトの右か左への傾きを表します。四元数を用いる主な利点は、ジンバルロックの影響を受けないことです。
四元数数学の込み入った内部処理はquaternionを参照しましょう。
rotationに関連する関数とイベントの一覧はRotation Synopsisを参照しましょう。
テクスチャの項にテクスチャの回転に関しての情報があります。
その他の表現
回転を表す他の手段は、<X,Y,Z>の3つからなる数値を、オブジェクトの各軸回りの回転量(ラジアン)として用いることです。これは例えばエディットウィンドウで用いられていて、人々が思い描くのがわりと容易です。この3つの数値はvectorであってrotation型では無いことに注意してください。ですがそれらは同じ情報を表すことができます。これは回転のオイラー角表現と呼ばれます。
3番目の方法は、前方、上方、そして左側を指す3つのvectorを用いることです。実際には3つのうち2つのみが必要で、3つめの値は2つから求めます。
回転を合成できるなどのもっともな理由があるので、4つの数値からなるrotationは優れているのですが、初心者が理解するのはより難しいです。幸いにも、実際のrotationの内部表現で何かすることはめったに必要ありませんし、また簡単にこれらの間を変換する関数があります。
右手ルール
LSLでは全ての回転が右手ルールに沿って行われています。右手で人差し指をx軸の正方向へ伸ばしてみてください。中指を人差し指から直角に伸ばすと、y軸の正方向を指します。そして親指を両指から直角に伸ばすとz軸の正方向を指します。あなたがオブジェクトを編集するとき、3色の軸の矢印は各軸(X: 赤, Y: 緑, Z: 青)の正方向を示します。
http://en.wikipedia.org/wiki/Right_hand_rule
さて、右手はまだ戻さないでください。正方向の回転の向きを求めるという別の使い道があります。右手を握り、親指を立てて好きな軸の正方向を指します。あなたの他の指は正方向の回転の向きに曲がります。x,y,z軸周りの回転は特に乗り物において、しばしばロール、ピッチ、ヨーとして示されます。
Rotationの結合
Rotationを結合するには、掛け算と割り算の演算子を用います。rotationへの足し算もしくは引き算の演算子は予期する動作にはならないので、使おうとはしないでください。掛け算の演算子は 方向の加算に、割り算の演算子は方向の引き算に応用されます。つまり、X.s = -X.sのような構成ではないということです。 float以外の型は、floatに変換されます。 non-commutativeが重要です。 rotatonへの変換はRLで重要で、理由は単純です。例えば、4つの羽のあるダーツを持っていたとして、rotation<0,0,0>の尾尻から始めて、有効なX軸方面に照準をつけ、羽をZとY軸のみにし、そしてダーツの軸とダーツ盤の軸を一直線上にします。私達はXを45度前後で、Yを30度前後回転させてやっていますが、それは間違いです。
始めに、X軸を45度回転の後にダーツはX軸上にまだあり、ぶれないまま、長時間軸にそって回転したあと、ダーツは軸を45度にするでしょう。Y軸を30度前後回転しているダーツは、X軸から30度XZ面へ降下するでしょう(rotationでのフレミングの法則は、降下移動したY軸の周囲で小さく有効に回転する、という意味だと思い出しましょう)。ダーツ風の上昇先を30度下げ、飛び始めと同じ高さを飛びますが、ダーツはそう長くは昇降せずに長時間軸に沿って回転されます。
ほかの方法を取るとするならば、最初にY軸を30度回転させて、ダーツがXZ面に回転降下するのでしょうが、X軸上にはそう長くはいないことに注目します。ダーツのX軸とダーツ板が一直線上にはならないからです。今X軸周りを45度回転するダーツは、ダーツの尾尻を中心にし、40度右上がり向きに、長時間有効なダーツ板のX軸が30度の円錐上にあるポイントへ従います。X軸へと降下しているように見えたなら、ダーツはX軸の30度以下のポイントから旋回し、右上がりにXZ面上から出て、XY面上の最初の四分儀以下のポイントへ、ダーツは回転して進みます。
明らかにこれは最初のrotationとは異なる結果ですが、rotationの結果が変えられるだけのことです。
ラジアンの構成(オイラーアングルと呼ばれる)でX、Y、Zアングルによるvectorで作成できうる値を定義する必要がある、rotation'の要素を定数のrotationにすることは、llEuler2Rot 関数にて用いるrotationに変換するということです。直に自然なrotationを代わる代わる作ることができます。実際の箇所はrotationのアングルの半分のコサインで、vectorの部分はrotationのアングルの半分のサインとrotationの標準的な角度を掛け算されたものです。llRot2Eulerを使ってrotationからオイラーアングルの vectorにしましょう。
NOTE:LSLのアングルはラジアンであって角度ではありませんが、ビルトイン定数RAD_TO_DEG と DEG_TO_RADを使うことで、簡単に変換できます。X軸周りの30度のrotationのために、あなたはこう使うこともできます。
rotation rot30X | = llEuler2Rot(<30, 0,0> * DEG_TO_RAD); | // 角度からラジアンに変換して、vectorをrotationのrot30Xに代入します。 |
vector vec30X | = llRot2Euler(rot30X ); | // rotationからvectorへ逆変換します。(値はラジアンとなるでしょう。) |
オイラーvector用のrotationの命令
上記の記述より、一つの軸以上に機能するrotationで対処するときにはっきりするのは、行われる命令が臨界ということです。この上記のオイラーの記述は、少しもっともらしい類で、3つの角度周りの単一のrotationは全体のrotationとして定義されますが、rotationは何度にすればいいのかという質問をされます。この答えはグローバル座標中のZ、Y、Xです。オイラーの描写を用いて、一回で一つの軸以上の周囲をオブジェクトが回転するように試すのなら、Z、Y、X rotationの順に用いた正しいオイラーvectorを決定して、オブジェクトに結合したrotationあるいは適用したrotationで用いるためのrotationを取得するためのllEuler2Rotを用います。
ローカル rotation vs グローバル rotation
インワールドに相対なrotationとローカルオブジェクト自身に相対なrotationとを区別することは重要です。エディタにて、お互いをいったりきたりさせることができます。スクリプトにて、望ましい振る舞いを得るために互いに変換させるべきです。
ローカルrotationは、どのようにインワールドにてオブジェクトが回転するかに関わらず、オブジェクト自身の前後、左右、上下に埋め込まれた角度の周りで行われます。グローバルrotationは、南北、東西、高低のインワールド角度周りにて行われます。プリムを編集してローカルとグローバル間で角度を変えると、どのように色づけされた角度の矢印が変わるか、プリムを回転させることで違いを見ることができます。
LSLでは、rotationをローカル'かグローバルにするかの違いは、ステートメントでrotationの評価される方法によります。
このrotationは、一定の30度のrotationへオブジェクトが左向きにrotation(myRot)を開始している状態によるものがローカルの30度のrotationです。最初の例であげた最初の演算の、ダーツ自身の長軸周りをダーツが30度ひねっているものようなものです。
rotation localRot = | rot30X * myRot; | // 空間のrotationによる、一定のrotationtで掛け算されたローカルのrotationを行ないます。 |
同じrotationの値を用いてグローバルrotationをすることは、その逆の命令ということではありません。これは2つめの例の2つめの演算で、ダーツが上昇回転して、空間のX軸にそって右に回るようなものです。このケースでは、存在しているrotation(myrot)はグローバルのX軸周りを30度回転しています。
rotation globalRot | = myRot * rot30X; | // 一定のrotationにより、空間のrotationで掛け算されたグローバルのrotationを行ないます。 |
rotationの結合について他の方法を考える
左右を括弧で覆われたものを除いて、評価する命令の中で行なわれるrotationを考えることにより、このローカル対グローバルの違いについて考えたくなるでしょう。
<0,0,0>から始まって発生するlocalRotのケースではrot30Xが最初に行なわれ、空間のX軸にそってプリムが回転し、回転している間は、ローカルとグローバルの角度はオブジェクトのローカルX軸に沿っての回転を行なう効果を識別します。2つめのrotationであるmyRotはプリムをオリジナルのrotationに回転させましたが、それではさらにX軸のrotationが焼きつきます。何と、これはプリムがX軸にそって回転して、YとZのrotationが変わらなかったローカルrotationのようなものです。
<0,0,0>から再び始まっているglobalRotのケースでは、最初にオブジェクトはオリジナルrotation(myrot)まで回転されますが、それではオブジェクトの角度と空間の角度は長くは調整されません。そこで、2つめのrotationであるrot30Xはローカルのケースで、オブジェクトを空間のX軸に沿って30度回転させ、確実に行ないますが、効果はオブジェクトのX軸と空間のX軸が今回一致しなくなってから、空間のX軸にそった円錐体をとおしてオブジェクトを回転することです。なんと、これはプリムが空間のX軸にそって30度旋回したもので、ゆえにグローバルrotationのようなものです。
rotationの割り算は、反対の方向のrotationにする効果があり、330度のrotationによる掛け算は、30度のrotationによる割り算と同じです。
rotationを使う
R.x、R.y、R.z、 そしてR.s(R.wではありません)によるrotationRの特定の構成でアクセスが可能です。スカラー部R.sはrotationのアングルの半分のコサインです。vector部(R.x、R.y、R.z)はrotationの一般的な角度とrotationのアングルの半分のサインの積です。x、y、zが無効になることによる(あるいは無効な値をつくることにより)、逆のrotationを生成可能です。余談ですが、float 値のリポジトリとしてrotationを使うことも可能で、各rotationは4つのfloat 値を貯蓄し、rotationから成り立つlistはfloatの集まりから成り立つlistよりもさらに効率的ですが、それの中身を覗くのはコストが高いでしょう。
rotation rot30X | = llEuler2Rot(<30, 0,0> * DEG_TO_RAD ); | // rotation定数を作成する |
rotation rotCopy | = rot30X; | // rotCopyに全4つのfloatの構成をコピーします |
float X | = rotCopy.x; | // rotationの特定の構成を出力します |
float Y | = rotCopy.y; | |
float Z | = rotCopy.z; | |
float S | = rotCopy.s; | |
rotation anotherCopy | = <X, Y, Z, S>; | // 構成から他のrotationを作ります |
直接、あるいはrotation Rを反転する必要があるならば、RによってZERO_ROTATIONを分割して使うことが出来る、zero rotationのビルトイン定数があります。上記の注意として、最初のzero potitionの回転による作業は 次にそれを分割させるため、オリジナルのrotationの逆向きに回転させ、その結果反転のrotationにします。
rotation rot330X | = <-rot30X.x, -rot30X.y, -rot30X.z, rot30X.s>; | // rotationの反転 - この構成は有効ではありません |
rotation another330X | = ZERO_ROTATION / rot30X; | // 割り算によるrotationの反転で、rot330Xと結果は同じです |
rotation yetanother330X | = <rot30X.x, rot30X.y, rot30X.z, -rot30X.s>; | // まったくの同じものではありませんが、同じ働きをします |
単一もしくはルートプリム vs リンクプリム vs アタッチメント
単一かリンクプリムのrotationについて話す理由は乗り物のドラのようなもののためで、期待された動作は、たとえ乗り物全体のrotationに何があろうとも、乗り物と相対的にドアが動くことです。可能な限りこれをグローバルrotationにする間は、手をつけることすらないでしょう。 プリムには独自で、linksetの一部、attachmentの一部があり、一般的な3つの等位なシステムがあります。プリムが独立しているとき、たとえばlinksetの一部ではなく、ルーとプリムのように動いたり、attachmentの一部のときは、ちょっと壊れたような異なる動きをします。
関数 | 地面の (rez'ed) プリム | アタッチメント プリム | ||
---|---|---|---|---|
単一かルート | リンクメンバ | 単一かルート | リンクメンバ | |
llGetRot llGPP:PRIM_ROTATION llGetObjectDetails |
プリムのグローバルrotation | プリムのグローバルrotation | アバタのグローバルrotation | アバタのグローバルrotation * プリムのグローバルrotation(使い勝手はよくありません) |
llGetLocalRot llGPP:PRIM_ROT_LOCAL/ja |
プリムのグローバルrotation | プリムのrotationと相対的なルートプリム | アタッチメントのrotationと相対的なアタッチポイント | ルートプロムのアタッチメントと相対的なプリムのrotation |
llGetRootRotation | プリムのグローバルrotation | ルートプリムのグローバルrotation | アバタのグローバルrotation | アバタのグローバルrotation |
llSetRot* llSPP:PRIM_ROTATION* |
グローバルrotationを設定します | 複雑です。llSetRotを参照します | アバタと相対的なrotationを設定します | ルートグローバルrotation* new_rotのrotationを設定します |
llSetLocalRot* llSPP:PRIM_ROT_LOCAL* |
グローバルrotationを設定します | ルートプリムと相対的なプリムのrotationを設定します | アバターの相対的なグローバルrotationを設定します | アタッチメントのルートプリムと相対的なプリムのrotationを設定します |
llTargetOmega† ll[GS]PP:PRIM_OMEGA |
プリムの中心周りをリンクされた全体が回転します | プリムの中心周りをプリムが回転します | アタッチメントの中心周りをリンクされた全体が回転します | アタッチメントの中心周りをプリムが回転します |
* | はリンクされた全体のうちの子プリムではない物理的オブジェクト はrotationの設定が反応しないでしょう。 |
† | 物理的オブジェクトではないもののために、 llTargetOmega はもしスムースな連続回転する方法を行なうならば、クライアントサイドで実行されます。 |
Vectorの回転
LSLで、rotationの中心がオブジェクトの中心はないときに輪や弧の中でオブジェクトを動かしたいのなら、vectorの回転はとても使い勝手がよいです。
とても整っていますが、目で見るものは殆どありません。上記のダーツの回転の議論を思い出しして、物理のダーツとvectorを、基点をダーツの尾尻、そしてX、Y、Zの構成ダーツの頂点のポジションと記述して、置き換えてみましょう。ダーツの尾尻にそって回転しているダーツは全体の頂点が移動し、rotationの中心はダーツの尾尻の弧です。まったく同じものは プリムの中心から同じ弧を通してプリムが回転する補正値を描写する、回転しているvectorです。なんと、これはオブジェクトがプリムの中心からのvector位置補正値周辺を回転するかのようにみえます。
rotation rot30X | = llEuler2Rot(<30, 0,0> * DEG_TO_RAD ); | // X軸周りの30度のrotationの定数を作成します |
vector offset | = <0, 1, 0>; | // グローバルの有効なY方向に補正値1メートルを作成します |
vector rotatedOffset | = offset * rot30X; | // rotationによって発生した動きを取得する補正値で回転します |
vector newPos | = llGetPos() + rotatedOffset; | // 補正値総数で回転したプリムのポジションを移動します |
Nota Bene: これによっておこなう移動は、10mもしくはそれ以下の地下に埋まっているオフワールドのプリムが移動する問題について忘れてはいけません。
定数
ZERO_ROTATION
ZERO_ROTATION = <0.0, 0.0, 0.0, 1.0>;
このrotation定数は<0.0, 0.0, 0.0>のオイラーアングルの代数です。
DEG_TO_RAD
DEG_TO_RAD = 0.01745329238f;
DEGREES(角度)のアングルをラジアンのアングルに渡して乗算するときのfloat定数です。
RAD_TO_DEG
RAD_TO_DEG = 57.29578f;
ラジアンのアングルをDEGREES(角度)のアングルに渡して乗算するときのfloat定数です。