Rotation/ja
LSL ポータル | 関数 | イベント | 型 | 演算子 | 定数 | 実行制御 | スクリプトライブラリ | カテゴリ別スクリプトライブラリ | チュートリアル |
Rotation
各要素は、変数名に .x
、.y
、.z
、または .s
を追加することで個別にアクセスできます。
rotation rot;
float x = rot.x;
float y = rot.y;
float z = rot.z;
float s = rot.s;
LSL のrotation型は3Dでの方位を表すのに用いられます。(型名を太字で書くように心がけています。)方位あるいは3Dアングルはクォータニオンと呼ばれる数学的オブジェクトによって表されます。クォータニオンは4つの数値から成ると考えることができ、3つがオブジェクトの向いている方向を表し、4つめがその方向の周りでのオブジェクトの右か左への傾きを表します。クォータニオンを用いる主な利点は、ジンバルロックの影響を受けないことです。 クォータニオン数学の込み入った内部処理はクォータニオンを参照してください。 rotationに関連する関数とイベントの一覧はRotation Synopsisを参照してください。 テクスチャの項にテクスチャの回転に関しての情報があります。
回転はしばしば非常に混乱するトピックと見なされ、スクリプターは試行錯誤して正確な結果を得ることがあります。この混乱の理由は次のとおりです:
- 誰もが本当の意味でクォータニオン が何であり、それをどのように考えるべきかを正確に知らない(完全には真実ではありませんが、脳は4つの幾何学的次元で考えることが得意ではありません)。
- 実際には異なるタイプのベクトル('dir'、'vec'、'pos')がいくつかあり、それぞれ異なる方法で操作する必要があります。
- 移動と回転を適用する順序はケースによって異なる場合があります。
- 適用された回転と座標系間の回転 'オフセット' の違いについて混乱があります。
したがって、回転をマスターするには、変数のための良い命名システムを使用することが不可欠です。このようなシステムは、About Coordinate Systems and Rotations で Timmy Foxclawによって詳しく説明されています。
その他の表現
Euler vector
3D角度を表す別の方法は、<X、Y、Z> という3つの数値を使用することです。これらの数値は、オブジェクトが各軸を中心に回転する量を表します。たとえば、これは編集ウィンドウで使用され、一般的には人々が視覚化しやすいです。編集ウィンドウでの回転 <x、y、z> 数値を調整し、オブジェクトの挙動を確認するのは簡単です。編集ウィンドウでは、数値は度数で表されます。つまり、直角は90度です。
LSLでは、これらの3つの角度は度数ではなくラジアンで表されます。つまり、直角はPI/2です。ラジアンは非常に幅広い度数のようなものです。 これらの3つの数値は、回転型ではなくベクトル型であり、同じ情報を表すことができます。これは3D角度の オイラー 表現と呼ばれます。LSLでは、zの周りの回転が最初に行われ、次にyの周り、最後にxの周りが行われます。
回転を表す他の手段は、<X,Y,Z>の3つからなる数値を、オブジェクトの各軸回りの回転量(ラジアン)として用いることです。これは例えばエディットウィンドウで用いられていて、人々が思い描くのがわりと容易です。この3つの数値はvectorであってrotation型では無いことに注意してください。ですがそれらは同じ情報を表すことができます。これは回転のオイラー角表現と呼ばれます。
3番目の方法は、前方、上方、そして左側を指す3つのvectorを用いることです。実際には3つのうち2つのみが必要で、3つめの値は2つから求めます。
回転を合成できるなどのもっともな理由があるので、4つの数値からなるrotationは優れているのですが、初心者が理解するのはより難しいです。幸いにも、実際のrotationの内部表現で何かすることはめったに必要ありませんし、また簡単にこれらの間を変換する関数があります。
軸に角度を加算
この方法では、地球が回転する軸を定義し、その軸と回転軸周りの回転量を定義して、rotation を与えます。
例えば、x-y平面(リージョン座標では北東)で45度のrotationを定義したい場合、軸をxとyの同じ量で指す必要がありますが、zは使用しません。軸は<1.0, 1.0, 0.0>になります。軸を定義する数値の絶対サイズはこの表現では重要ではありません。例えば、<2.0, 2.0, 0.0>でも同様に動作します。rotationの角度は別のラジアンで与えられ、例えばPI/3(60度)です。これらの数値は、北東軸周りの60度のグローバルなrotationを定義します。
軸に角度を加算も四つの数値を使用しますが、"正規化"される必要はありません。
FWD, LEFT, UP
同じ3Dの角度を表現する別の方法は、前方が何を指しているか(fwd)、上部が何を指しているか(up)、そして左側が何を指しているか(left)を示す3つのベクトルを使用することです。 実際には、3つのうちの2つだけが必要です。 なぜなら、2つのベクトルを使用すると、残りの1つを決定できるからです。
良い理由があるため、例えばrotationを簡単に組み合わせることができるように、四つの数値バージョンであるクォータニオンのrotationがより良いですが、初心者にとって理解が難しいかもしれません。 幸いなことに、rotationの実際の内部表現で何かを行う必要があることはほとんどなく、3つのLSLタイプと度とラジアンの間を簡単に変換するための関数が存在します。
右手ルール
LSLでは全ての回転が右手ルールに沿って行われています。右手で人差し指をx軸の正方向へ伸ばしてみてください。中指を人差し指から直角に伸ばすと、y軸の正方向を指します。そして親指を両指から直角に伸ばすとz軸の正方向を指します。あなたがオブジェクトを編集するとき、3色の軸の矢印は各軸(X: 赤, Y: 緑, Z: 青)の正方向を示します。
http://ja.wikipedia.org/wiki/右手の法則
さて、右手はまだ戻さないでください。正方向の回転の向きを求めるという別の使い道があります。右手を握り、親指を立てて好きな軸の正方向を指します。あなたの他の指は正方向の回転の向きに曲がります。x,y,z軸周りの回転は特に乗り物において、しばしばロール、ピッチ、ヨーとして示されます。
http://ja.wikipedia.org/wiki/ローリング ・ http://ja.wikipedia.org/wiki/ピッチング ・ http://ja.wikipedia.org/wiki/ヨーイング
Rotationの合成
考えてみましょう。2つの回転があると仮定しましょう。r1 は左に90度回転し、r2 は右に30度回転します。(どの回転でも構いません;これは単なる例です。)
- 演算子を使用して r1 と r2 を結合して、r3 を作成できます。実際にはそれらを「掛け算」するのではなく、それらを「合成」します。
rotation r3 = r1 * r2;
Rotationを合成するには、掛け算と割り算の演算子を用います。rotationへの足し算もしくは引き算の演算子は予期する動作にはならないので、使おうとはしないでください。掛け算の演算子は 正方向の回転に、割り算の演算子は負方向の回転に用いられます。X.s = -X.sのようにして成分sを直接反転させて回転を反転させることもできます。
他のデータ型(例:float)とは異なり、操作の順序、非可換、が重要です。その理由は単純です。回転を行う順序はRLで重要です。たとえば、4本の羽を持つダーツを、回転 <0, 0, 0> から始め、その尾が原点にある状態から考えてみましょう。これはX軸に沿っており、先が正のX方向を指しており、羽はZ軸とY軸に沿っています。ダーツの軸と世界の軸が揃っています。これをX軸を中心に45度回転させ、Y軸を中心に30度回転させることになりますが、異なる順序で行います。
最初に、X軸を中心に45度回転すると、ダーツはX軸上にあり、移動せず、ただ長い軸に沿って回転します。したがって、羽は軸に対して45度の角度を持つことになります。次に、Y軸を中心に30度回転すると、ダーツはXZ平面内でX軸から30度下を指すようになります(回転の右手ルールによれば、Y軸を中心に小さな正の回転は点を下に移動させます)。ダーツは下を向いており、始めにいたのと同じ垂直平面にありますが、自分自身の長い軸を中心に回転しているため、羽が上下ではなくなっています。
逆の順序で行った場合、まずY軸を中心に30度回転すると、ダーツはXZ平面内で下に回転しますが、注意してください、もはやX軸上にはありません。ダーツのX軸と世界のX軸はもはや揃っていません。今度はX軸を中心に45度回転させると、ダーツは尾を中心に回転し、点はX軸が正の方向にある世界のXY平面の第1象限の下にある点へと移動します。羽も回転しながら移動します。
明らかに、これは最初の回転とは異なる結果ですが、回転の順序が変更されただけです。
一定の回転を行うには、X、Y、Zの角度を成分として持つvectorを作成し(これはオイラー角と呼ばれます)、それをllEuler2Rot関数を使用してrotationに変換する必要があります。回転からオイラー角に変換するには、llRot2Eulerを使用します。
軸回転を行いたい場合は、回転の軸と回転角度をllAxisAngle2Rot関数に挿入し、これによりrotationが返されます。回転から軸と角度に戻すには、llRot2AxisとllRot2Angleを使用します。
代替方法として、ネイティブな回転を直接作成することもできます。実数部分は回転角の半分の余弦であり、ベクトル部分は回転の軸を正規化し、角度の半分の正弦で乗算したものです。
NOTE:LSLでの角度はラジアンであって度ではありませんが、組み込み定数RAD_TO_DEG と DEG_TO_RADを使うことで簡単に変換できます。X軸周りの30度のrotationに対して以下のように使うこともできます:
rotation rot30X = llEuler2Rot(<30, 0, 0>*DEG_TO_RAD); // 度をラジアンに変換してから、{{LSLG/ja|vector|vector}}をrotationのrot30xに代入します。
vector vec30X = llRot2Euler(rot30X); // rotationから{{LSLG/ja|vector|vector}}へ逆変換します。(値はラジアンとなるでしょう。)
rotation rot30X = llAxisAngle2Rot(<1, 0, 0>, 30.0*DEG_TO_RAD); // 度をラジアンに変換してから、ラジアンの値をrot30xに変換します
Differences between math's quaternions and LSL rotations
数学のクォータニオンとLSLの回転にはいくつかの違いがあり、スクリプトを作成する際にはあまり影響がないかもしれませんが、数学の知識を持つ人々を困惑させる可能性があるため、それらをここにリストアップすることが良いと考えました。:
- LSLでは、すべてのクォータニオンは正規化されています(RによるRの内積は常に1です)。したがって、オブジェクトのサイズを変更せずに回転させる方法を表します。数学では、一般的なクォータニオンは正規化されていない場合があり、オブジェクトのサイズを変更する方法を表します。
- LSLでは、sの項目は回転の4番目のメンバーです:<x, y, z, s>。数学では、sの項目、または「実部」とも呼ばれるものは、クォータニオンの最初の座標として書かれます:(s, x, y, z)。
- 乗算はLSLと数学では逆の順序で書かれています。LSLでは、R * Sと書きますが、数学ではS . Rと書きます。
オイラーベクトルでの回転の順番
上述の議論より1つ以上の軸で回転する場合、それらの回転する順番が重要となるのは明らかです。オイラーの議論ではこれはちょっと少しごまかしました。3つの軸周りの個々の回転は総合的な回転を定義します。しかし、それでは疑問が浮かびます: どんな軸の順番で回転しているのか? その答えはグローバル座標系ではZ,Y,Xです。オブジェクトをオイラー表現を用いて1つ以上の軸で同時に回転させたい場合、現在のオイラーvectorをZ, Y, X回転の順に決定し、回転の合成またはオブジェクトへ回転を適用させるためのrotationを得るためにllEuler2Rot関数を使います。
ローカル vs グローバル(ワールド)rotation
ワールドのrotationとオブジェクト自体のローカルのrotationとを区別することは重要です。エディタでは、あなたは一方からもう片方へと切り替えることができます。 スクリプトではあなたは要求する振る舞いを得るために一方から他方へと変換しなければなりません。
ローカルの回転は、オブジェクトがワールド内でどんな回転をしているかに関わらないオブジェクト自身の前後、左右、上下に当てはめられた軸周りでの回転です。グローバルの回転は南北、東西、上下のワールドの軸周りでの回転です。あなたはプリムの回転の違いを見ることができ、編集やローカルとグローバルの軸の設定を色のついた矢印が変わるの注意しながら変更することができます。
LSLではローカルとグローバルの回転の違いは、ステートメント内でrotationが評価される順番の違いとなります。
これは、30度の一定のrotationをオブジェクトの最初のrotation(myRot)の左側につけることでローカルでの30度の回転を行います。それは上述のダーツをその長軸の周りに30度にねじる最初の例の最初の操作に似ています。
rotation localRot = rot30X * myRot;// ワールドの回転に一定の回転をかけることでローカルの回転を行う。
グローバルの回転をするためには同じrotationを使いますが、順番は逆にしてください。これはダーツが上昇回転してワールドのX軸周りに右に回る2番目の例の2番目の操作に似ています。この場合、既存のrotation(myRot)はグローバルのX軸の周りで30度回転します。
rotation globalRot = myRot * rot30X;// 一定の回転をワールドの回転にかけることでグローバルの回転を行う。
rotationの結合について考える他の方法
あなたはローカルとグローバルの違いについて、括弧以外は左から右へと評価されるというrotationの評価順序から考えてみたいかもしれません。
localRotの場合は、<0, 0, 0>から始まって、rot30Xが最初に行われ、ワールドのX軸回りにプリムが回転し、回転の始まる時点からローカルとグローバルの軸はオブジェクトのローカルのX軸に沿った同一の回転をします。 そして、2つめのrotationであるmyRotは、プリムをオリジナルのrotationで回転させましたが、さらにX軸の回転が焼きつきます。 これは、プリムの回転がそのX軸に沿ってYとZのrotationが変わらないローカル回転のようになります。
globalRotの場合は、再び<0, 0, 0>から始まって、まずオブジェクトがオリジナルのrotation(myRot)で回転しますが、オブジェクトの軸とワールドの軸はもはや一致しません!そして、2つめのrotationであるrot30xは、まさにローカルの場合と同様に、オブジェクトをワールドのX軸回りに30度回転しますが、その効果はオブジェクトをワールドのX軸に沿って円錐を回転させます。オブジェクトのX軸とワールドのX軸はこの時点では一致しません。プリムはワールドのX軸の沿って30度回転するように見えます。そのためglobal rotationのようになります。
rotationの割り算は、反対方向のrotationにする効果があり、330度のrotationによる掛け算は、30度のrotationによる割り算と同じです。
rotationを使う
rotation Rのそれぞれの要素にはR.x, R.y, R.zとR.s (R.wではありません)からアクセスできます。スカラ部分のR.sは回転角の2分の1のコサインです。ベクタ部分(R.x,R.y,R.z)は正規化した回転軸と回転角の2分の1のサインの積です。x,y,z要素の符号を反転することにより(または、sの符号を反転させることにより)逆の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を作ります
ゼロ回転の組み込み定数としてZERO_ROTATIONがあり、rotation Rを反転させたい場合はZERO_ROTATIONをRで割ります。上記の注意として、これはまずゼロ位置への回転となり、そして除算なので元のrotationの反対向きへの回転となり、その結果逆回転します。
rotation rot330X = <-rot30X.x, -rot30X.y, -rot30X.z, rot30X.s>;// 回転の反転 - 注意 要素sの符号は反転していません
rotation another330X = ZERO_ROTATION / rot30X; // 除算による回転の反転、rot330Xと同じ結果となります
rotation yetanother330X = <rot30X.x, rot30X.y, rot30X.z, -rot30X.s>; // まったく同じではありませんが同じ結果となります。
単一またはルートプリム vs リンクプリム vs アタッチメント
単一またはリンクプリムの回転について語る理由として、どんなビークル全体の回転があっても対応してドアが動くという望ましい動きするビークルのドアなどのためです。グローバルな回転でこれを行える間はそれはとても退屈でしょう。通常、プリムが扱える座標系には単独、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ではvectorを回転させるのは回転の中心がオブジェクトの中心ではないオブジェクトを弧や円状に動かしたいときにとても役立ちます。
これはとても複雑に思えますが、これにはここで目にするより多くのことがあります。上述のダーツに関する議論を思い出して、物理的なダーツを元点がダーツの尾部にありダーツの先端の位置をX,Y,Z要素とするvectorに置き換えてみてください。ダーツの尾部回りの回転はダーツの先端をダーツの尾部を中心とした弧に沿って動かします。まさに同様にプリムの中心からずれを表すvectorの回転は同じ弧を通りプリムを回転させます。これはvectorによりプリムの中心からずれた位置の周りでのオブジェクトの回転に見えます。
rotation rot6X | = llEuler2Rot(<30, 0, 0> * DEG_TO_RAD ); | // localのX軸回りに30度するrotationの定数を作成する |
vector offset | = <0, 1, 0>; | // localのY方向へ正の向きで1mのオフセットを作成する |
vector rotatedOffset | = offset * rot6X; | // rotationによる動きを得るためにオフセットを回転する |
vector newPos | = llGetPos() + (offset - rotatedOffset) * llGetRot(); | // 回転したオフセット分だけプリムの位置を動かします |
rotation newRot | = rot6X * llGetRot(); | // オフセット点を向くために回転を変更します |
//-- same as:
llSetPrimitiveParams( [PRIM_POSITION, llGetPos() + (gPosOffset - gPosOffset * gRotArc) * llGetRot(),
PRIM_ROTATION, gRotArc * llGetRot()] );
注意: これによる移動はプリムを地下や10m以上移動させる結果にもなることを忘れないでください。
オブジェクトの現在の向きに対応した点を得る(rezzorsなどに使います)
//-- same as:
vector correctOffset = llGetPos() + offset * llGetRot();
Position of Object Rotated Around A Relative Point
rotation vRotArc = llEuler2Rot( <30.0, 0.0, 0.0> * DEG_TO_RAD );
//-- creates a rotation constant, 30 degrees around the X axis
vector vPosOffset = <0.0, 1.0, 0.0>;
//-- creates an offset one meter in the positive Y direction
vector vPosRotOffset = vPosOffset * vRotArc;
//-- rotates the offset to get the motion caused by the rotation
vector vPosOffsetDiff = vPosOffset - vPosRotOffset;
//-- gets the local difference between the current offset and the rotated one
vector vPosRotDiff = vPosOffsetDiff * llGetRot();
//-- rotates the difference in the offsets to be relative to the global rotation.
vector vPosNew = llGetPos() + vPosRotDiff;
//-- finds the prims new position by adding the rotated offset difference
rotation vRotNew = vRotArc * llGetRot();
//-- finds rot to continue facing offset point
- アプリケーションにおいて、以下の操作が行われています:
llSetPrimitiveParams( [PRIM_POSITION, llGetPos() + (vPosOffset - vPosOffset * vRotArc) * llGetRot(),
PRIM_ROTATION, vRotArc * llGetRot()] );
- 上記の方法では、周回しているオブジェクトは常に中心に対して同じ側面を向いています。回転を保持する代替方法は次の通りです
llSetPrimitiveParams( [PRIM_POSITION, llGetPos() + (vPosOffset - vPosOffset * vRotArc) * llGetRot()];
vPosOffset = vPosOffset * vRotArc;
注意 これは移動操作ですので、オブジェクトをワールドの外に移動させたり、地下に埋めたり、10メートル以上移動させる場合の問題に注意してください。また、完全な軌道を得るためには、リストされたステップを繰り返す必要があります(タイマーを使用することができます)。
注意 これらはルートプリム(または好みに応じた子プリム)に適用されます。子プリムの場合、位置にはPRIM_POS_LOCALを、回転にはPRIM_ROT_LOCALまたはllGetLocalRotを使用し、回転の中心はルートに対して相対的である必要があります。
Position of Relative Point Around Rotated Object
オブジェクトの現在の向きに対して相対的なポイントを取得するには(rezzorsなどで使用されることがあります)、次のようにします。
vector vPosOffset = <0.0, 0.0, 1.0>;
//-- creates an offset one meter in the positive Z direction.
vector vPosRotOffset = vPosOffset * llGetRot();
//-- rotate the offset to be relative to objects rotation
vector vPosOffsetIsAt = llGetPos() + vPosRotOffset;
//-- get the region position of the rotated offset
- アプリケーションにおいて、以下の操作が行われています:
llRezAtRoot( "Object", llGetPos() + vPosOffset * llGetRot(), ZERO_VECTOR, ZERO_ROTATION, 0 );
Normalizing a Rotation
正確性が必要な場合、正規化された回転を使用することはしばしば重要であり、必要なことさえあります。これは、各四元数の 'x'、'y'、および 'z' の値が1に等しくなるようにスケーリングすることを意味します。LSLのいくつかの操作は、これを行わないと実行時エラーが発生する場合があります。別の視点で見ると、回転を、ベクトル<1.0、1.0、1.0>に回転角を適用する方法で表現する必要があります。数学的に、回転 'Q' を正規化することは次のように計算されます。
Normalized Q = Q / Sqrt( Q.x^2 + Q.y^2 + Q.z^2 + Q.s^2)
Putting that in LSL terms:
rotation NormRot(rotation Q)
{
float MagQ = llSqrt(Q.x*Q.x + Q.y*Q.y +Q.z*Q.z + Q.s*Q.s);
return <Q.x/MagQ, Q.y/MagQ, Q.z/MagQ, Q.s/MagQ>;
}
- Note: 正規化されていない回転を取得するLSLの唯一の方法は、llAxes2Rot/ja('相互に直交していない入力'または '異なる大きさの入力'を介して)または回転の要素を直接操作することです。他のすべてのll*関数は正規化された回転を返します。前述の例の使用により、有限の精度の制約により、正規化された回転に小さな浮動小数点エラーが導入される可能性があります。
便利なスニペット
文字列がRotationか判定
integer IsRotation(string s)
{
list split = llParseString2List(s, [" "], ["<", ">", ","]);
if(llGetListLength(split) != 9)//リスト長のチェックをしないと次のテストが正しく動きません
return 0;
return !((string)((rotation)s) == (string)((rotation)((string)llListInsertList(split, ["-"], 7))));
//it works by trying to flip the sign on the S element of the rotation,
//if it works or breaks the rotation then the values won't match.
//if the rotation was already broken then the sign flip will have no affect and the values will match
//we cast back to string so we can catch negative zero which allows for support of <0,0,0,0>
}//Strife Onizuka
rotation をRoll Pitch Yawに分割
// LindaB Helendale
// https://wiki.secondlife.com/wiki/User:LindaB_Helendale/rot2roll_pitch_yaw
vector rot2roll_pitch_yaw(rotation R)
{
/*
Convert rotation to roll, pitch and yaw angles
(c) LindaB Helendale
Permission to use this code in any way granted
Input: rotation (quaternion) R
Output: vector <roll,pitch,yaw>
Roll, pitch and yaw are body-related rotations (intrinsic Tait-Bryan angles):
first yaw to the heading, then pitch around the local Y-axis and then roll
around the local X-axis (nose direction). This is equivalent to world coordinate
rotations (extrinsic Tait-Bryan angles, or LSL Euler angles) in order roll, pitch and yaw.
Thus the rotation R is recovered from the roll, pitch and yaw angles by inverting
the order of the rotations (since in LSL they are in Z Y X or yaw, pitch, roll order):
rotation R = llEuler2Rot(<roll,0,0>) * llEuler2Rot(<0,pitch,0>) * llEuler2Rot(<0,0,yaw>);
Reference: http://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles
*/
vector eulerXYZ = < llAtan2(2*(R.s*R.x+R.y*R.z),1-2*(R.x*R.x+R.y*R.y)),
llAsin(2*(R.s*R.y-R.z*R.x)),
llAtan2(2*(R.s*R.z+R.x*R.y), 1-2*(R.y*R.y+R.z*R.z)) >;
return(eulerXYZ);
}
Roll Pitch Yawをrotationに変換
// LindaB Helendale
// https://wiki.secondlife.com/wiki/User:LindaB_Helendale/rot2roll_pitch_yaw
rotation roll_pitch_yaw2rot(vector R)
{
// convert vector <roll,pitch,yaw> to LSL rotation
return llEuler2Rot(<R.x,0,0>) * llEuler2Rot(<0,R.y,0>) * llEuler2Rot(<0,0,R.z>);
}
定数
ZERO_ROTATION
ZERO_ROTATION = <0.0, 0.0, 0.0, 1.0>;
オイラー角の<0.0, 0.0, 0.0>に相当するrotation定数
DEG_TO_RAD
DEG_TO_RAD = 0.01745329238f;
角度(°)から乗算でラジアン角を得るときのfloat定数
RAD_TO_DEG
RAD_TO_DEG = 57.29578f;
ラジアン角から乗算で角度(°)を得るときのfloat定数