Difference between revisions of "Rotation/ja"
m |
m |
||
Line 1: | Line 1: | ||
{{Multi-lang}} | {{Multi-lang}} | ||
{{LSL Header/ja}}{{RightToc}} | {{LSL Header/ja}}{{RightToc}} | ||
=Rotation= | ==Rotation== | ||
[[rotation/ja|回転]] は 4つの[[float/ja|浮動小数点値]] を含む{{LSLGC|Types|データ型}}です。 | |||
各要素は、変数名に <code>.x</code>、<code>.y</code>、<code>.z</code>、または <code>.s</code> を追加することで個別にアクセスできます。 | |||
<source lang="lsl2">rotation rot; | |||
float x = rot.x; | |||
float y = rot.y; | |||
float z = rot.z; | |||
float s = rot.s;</source> | |||
LSL の'''rotation'''型は3Dでの方位を表すのに用いられます。(型名を'''太字'''で書くように心がけています。)方位あるいは3Dアングルは{{LSLG/ja|quaternion|クォータニオン}}と呼ばれる数学的オブジェクトによって表されます。クォータニオンは4つの数値から成ると考えることができ、3つがオブジェクトの向いている方向を表し、4つめがその方向の周りでのオブジェクトの右か左への傾きを表します。クォータニオンを用いる主な利点は、[http://en.wikipedia.org/wiki/Gimbal_Lock ジンバルロック]の影響を受けないことです。 | LSL の'''rotation'''型は3Dでの方位を表すのに用いられます。(型名を'''太字'''で書くように心がけています。)方位あるいは3Dアングルは{{LSLG/ja|quaternion|クォータニオン}}と呼ばれる数学的オブジェクトによって表されます。クォータニオンは4つの数値から成ると考えることができ、3つがオブジェクトの向いている方向を表し、4つめがその方向の周りでのオブジェクトの右か左への傾きを表します。クォータニオンを用いる主な利点は、[http://en.wikipedia.org/wiki/Gimbal_Lock ジンバルロック]の影響を受けないことです。 | ||
クォータニオン数学の込み入った内部処理は{{LSLG/ja|quaternion|クォータニオン}}を参照してください。 | クォータニオン数学の込み入った内部処理は{{LSLG/ja|quaternion|クォータニオン}}を参照してください。 | ||
rotationに関連する関数とイベントの一覧は{{LSLG/ja|Rotation Synopsis|Rotation Synopsis}}を参照してください。 | rotationに関連する関数とイベントの一覧は{{LSLG/ja|Rotation Synopsis|Rotation Synopsis}}を参照してください。 | ||
{{LSLG/ja|texture|テクスチャ}}の項にテクスチャの回転に関しての情報があります。 | |||
回転はしばしば非常に混乱するトピックと見なされ、スクリプターは試行錯誤して正確な結果を得ることがあります。この混乱の理由は次のとおりです: | |||
* 誰もが本当の意味で[[quaternion/ja|クォータニオン]] が何であり、それをどのように考えるべきかを正確に知らない(完全には真実ではありませんが、脳は4つの幾何学的次元で考えることが得意ではありません)。 | |||
* 実際には異なるタイプのベクトル('dir'、'vec'、'pos')がいくつかあり、それぞれ異なる方法で操作する必要があります。 | |||
* 移動と回転を適用する順序はケースによって異なる場合があります。 | |||
* 適用された回転と座標系間の回転 'オフセット' の違いについて混乱があります。 | |||
したがって、回転をマスターするには、変数のための良い命名システムを使用することが不可欠です。このようなシステムは、[[User:Timmy_Foxclaw/About_Coordinate_Systems_and_Rotations|About Coordinate Systems and Rotations]] で [[User:Timmy_Foxclaw|Timmy Foxclaw]]によって詳しく説明されています。 | |||
==その他の表現== | ==その他の表現== | ||
===Euler vector=== | |||
3D角度を表す別の方法は、<X、Y、Z> という3つの数値を使用することです。これらの数値は、オブジェクトが各軸を中心に回転する量を表します。たとえば、これは編集ウィンドウで使用され、一般的には人々が視覚化しやすいです。編集ウィンドウでの回転 <x、y、z> 数値を調整し、オブジェクトの挙動を確認するのは簡単です。編集ウィンドウでは、数値は度数で表されます。つまり、直角は90度です。 | |||
LSLでは、これらの3つの角度は度数ではなく{{LSLG/ja|radians|ラジアン}}で表されます。つまり、直角はPI/2です。ラジアンは非常に幅広い度数のようなものです。 | |||
これらの3つの数値は、回転型ではなくベクトル型であり、同じ情報を表すことができます。これは3D角度の ''オイラー'' 表現と呼ばれます。'''LSLでは、zの周りの回転が最初に行われ、次にyの周り、最後にxの周りが行われます'''。 | |||
回転を表す他の手段は、<X,Y,Z>の3つからなる数値を、オブジェクトの各軸回りの回転量({{LSLG/ja|radians|ラジアン}})として用いることです。これは例えばエディットウィンドウで用いられていて、人々が思い描くのがわりと容易です。この3つの数値は'''vector'''であって'''rotation'''型では無いことに注意してください。ですがそれらは同じ情報を表すことができます。これは回転のオイラー角表現と呼ばれます。 | 回転を表す他の手段は、<X,Y,Z>の3つからなる数値を、オブジェクトの各軸回りの回転量({{LSLG/ja|radians|ラジアン}})として用いることです。これは例えばエディットウィンドウで用いられていて、人々が思い描くのがわりと容易です。この3つの数値は'''vector'''であって'''rotation'''型では無いことに注意してください。ですがそれらは同じ情報を表すことができます。これは回転のオイラー角表現と呼ばれます。 | ||
Line 16: | Line 37: | ||
回転を合成できるなどのもっともな理由があるので、4つの数値からなる'''rotation'''は優れているのですが、初心者が理解するのはより難しいです。幸いにも、実際の''rotation''の内部表現で何かすることはめったに必要ありませんし、また簡単にこれらの間を変換する関数があります。 | 回転を合成できるなどのもっともな理由があるので、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タイプと度とラジアンの間を簡単に変換するための関数が存在します。 | |||
==右手ルール== | ==右手ルール== | ||
Line 27: | Line 60: | ||
==Rotationの合成== | ==Rotationの合成== | ||
考えてみましょう。2つの回転があると仮定しましょう。''r1'' は左に90度回転し、''r2'' は右に30度回転します。(どの回転でも構いません;これは単なる例です。) | |||
* 演算子を使用して ''r1'' と r2 を結合して、''r3'' を作成できます。実際にはそれらを「掛け算」するのではなく、それらを「合成」します。 | |||
<source lang="lsl2"> | |||
rotation r3 = r1 * r2; | |||
</source> | |||
'''Rotation'''を合成するには、'''掛け算'''と'''割り算'''の演算子を用います。'''rotation'''への足し算もしくは引き算の演算子は予期する動作にはならないので、使おうとはしないでください。'''掛け算'''の演算子は | '''Rotation'''を合成するには、'''掛け算'''と'''割り算'''の演算子を用います。'''rotation'''への足し算もしくは引き算の演算子は予期する動作にはならないので、使おうとはしないでください。'''掛け算'''の演算子は | ||
正方向の回転に、'''割り算'''の演算子は負方向の回転に用いられます。X.s = -X.sのようにして成分sを直接反転させて回転を反転させることもできます。 | 正方向の回転に、'''割り算'''の演算子は負方向の回転に用いられます。X.s = -X.sのようにして成分sを直接反転させて回転を反転させることもできます。 | ||
他のデータ型(例:{{LSLG/ja|float|float}})とは異なり、操作の順序、[http://ja.wikipedia.org/wiki/%E4%BA%A4%E6%8F%9B%E6%B3%95%E5%89%87 非可換]、が重要です。その理由は単純です。回転を行う順序は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の角度を成分として持つ{{LSLG/ja|vector}}を作成し(これはオイラー角と呼ばれます)、それを{{LSLG/ja|llEuler2Rot}}関数を使用して{{LSLG/ja|rotation}}に変換する必要があります。回転からオイラー角に変換するには、{{LSLG/ja|llRot2Euler}}を使用します。 | |||
軸回転を行いたい場合は、回転の軸と回転角度を{{LSLG/ja|llAxisAngle2Rot}}関数に挿入し、これにより{{LSLG/ja|rotation}}が返されます。回転から軸と角度に戻すには、{{LSLG/ja|llRot2Axis}}と{{LSLG/ja|llRot2Angle}}を使用します。 | |||
代替方法として、ネイティブな回転を直接作成することもできます。実数部分は回転角の半分の余弦であり、ベクトル部分は回転の軸を正規化し、角度の半分の正弦で乗算したものです。 | |||
'''NOTE:'''LSLでの角度はラジアンであって度ではありませんが、組み込み定数[[#RAD_TO_DEG|RAD_TO_DEG]] と [[#DEG_TO_RAD|DEG_TO_RAD]]を使うことで簡単に変換できます。X軸周りの30度の'''rotation'''に対して以下のように使うこともできます: | '''NOTE:'''LSLでの角度はラジアンであって度ではありませんが、組み込み定数[[#RAD_TO_DEG|RAD_TO_DEG]] と [[#DEG_TO_RAD|DEG_TO_RAD]]を使うことで簡単に変換できます。X軸周りの30度の'''rotation'''に対して以下のように使うこともできます: | ||
< | <source lang="lsl2"> | ||
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に変換します | |||
</source> | |||
== Differences between math's quaternions and LSL rotations == | |||
</ | |||
There are a few differences between LSL and maths that have little consequences while scripting, but that might puzzle people with prior mathematical knowledge. So we thought it would be good to list them here: | |||
* In LSL, all quaternions are normalized (the dot product of '''R''' by '''R''' is always '''1'''), and therefore represent ways to rotate objects without changing their size. In maths, generic quaternions might be not normalized, and they represent ''affinities'', i.e. a way to rotate '''and''' change the size of objects. | |||
* In LSL, the '''s''' term is the fourth member of the rotation: '''<x, y, z, s>'''. In maths, the '''s''' term, also called "real part", is written as the first coordinate of the quaternion: '''(s, x, y, z)'''. | |||
* Multiplication is written in reverse order in LSL and in maths. In LSL, you would write '''R * S''', where in maths you would write '''S . R'''. | |||
==オイラーベクトルでの回転の順番== | ==オイラーベクトルでの回転の順番== | ||
Line 65: | Line 112: | ||
これは、30度の一定の'''rotation'''をオブジェクトの最初の'''rotation'''(myRot)の左側につけることで'''ローカル'''での30度の回転を行います。それは上述のダーツをその長軸の周りに30度にねじる最初の例の最初の操作に似ています。 | これは、30度の一定の'''rotation'''をオブジェクトの最初の'''rotation'''(myRot)の左側につけることで'''ローカル'''での30度の回転を行います。それは上述のダーツをその長軸の周りに30度にねじる最初の例の最初の操作に似ています。 | ||
< | <source lang="lsl2"> | ||
rotation localRot = rot30X * myRot;// ワールドの回転に一定の回転をかけることでローカルの回転を行う。 | |||
</source> | |||
'''グローバル'''の回転をするためには同じ'''rotation'''を使いますが、順番は逆にしてください。これはダーツが上昇回転してワールドのX軸周りに右に回る2番目の例の2番目の操作に似ています。この場合、既存のrotation(myRot)はグローバルのX軸の周りで30度回転します。 | '''グローバル'''の回転をするためには同じ'''rotation'''を使いますが、順番は逆にしてください。これはダーツが上昇回転してワールドのX軸周りに右に回る2番目の例の2番目の操作に似ています。この場合、既存のrotation(myRot)はグローバルのX軸の周りで30度回転します。 | ||
< | <source lang="lsl2"> | ||
rotation globalRot = myRot * rot30X;// 一定の回転をワールドの回転にかけることでグローバルの回転を行う。 | |||
</source> | |||
==rotationの結合について考える他の方法== | ==rotationの結合について考える他の方法== | ||
Line 97: | Line 138: | ||
'''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'''を作ることができます。余談ですが、{{LSLG/ja|float|float}}値の格納場所として'''rotation'''を使うことも可能です。各'''rotation'''は4つの{{LSLG/ja|float|float}} 値を格納し、'''rotation'''から成る{{LSLG/ja|list|list}}は{{LSLG/ja|float|float}}の集まりの{{LSLG/ja|list|list}}よりもさらに効率的ですが中身を覗くのはコストが高いでしょう。 | '''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'''を作ることができます。余談ですが、{{LSLG/ja|float|float}}値の格納場所として'''rotation'''を使うことも可能です。各'''rotation'''は4つの{{LSLG/ja|float|float}} 値を格納し、'''rotation'''から成る{{LSLG/ja|list|list}}は{{LSLG/ja|float|float}}の集まりの{{LSLG/ja|list|list}}よりもさらに効率的ですが中身を覗くのはコストが高いでしょう。 | ||
< | <source lang="lsl2"> | ||
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を作ります | |||
</source> | |||
ゼロ回転の組み込み定数として[[#ZERO_ROTATION|ZERO_ROTATION]]があり、'''rotation R'''を反転させたい場合は[[#ZERO_ROTATION|ZERO_ROTATION]]を'''R'''で割ります。上記の注意として、これはまずゼロ位置への回転となり、そして除算なので元の'''rotation'''の反対向きへの回転となり、その結果逆回転します。 | ゼロ回転の組み込み定数として[[#ZERO_ROTATION|ZERO_ROTATION]]があり、'''rotation R'''を反転させたい場合は[[#ZERO_ROTATION|ZERO_ROTATION]]を'''R'''で割ります。上記の注意として、これはまずゼロ位置への回転となり、そして除算なので元の'''rotation'''の反対向きへの回転となり、その結果逆回転します。 | ||
< | <source lang="lsl2"> | ||
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>; // まったく同じではありませんが同じ結果となります。 | |||
</source> | |||
==単一またはルートプリム vs リンクプリム vs アタッチメント == | ==単一またはルートプリム vs リンクプリム vs アタッチメント == | ||
Line 141: | Line 167: | ||
これはとても複雑に思えますが、これにはここで目にするより多くのことがあります。上述の[[#Combining Rotations|ダーツ]]に関する議論を思い出して、物理的なダーツを元点がダーツの尾部にありダーツの先端の位置をX,Y,Z要素とする{{LSLG/ja|vector|vector}}に置き換えてみてください。ダーツの尾部回りの回転はダーツの先端をダーツの尾部を中心とした弧に沿って動かします。まさに同様にプリムの中心からずれを表す{{LSLG/ja|vector|vector}}の回転は同じ弧を通りプリムを回転させます。これは{{LSLG/ja|vector|vector}}によりプリムの中心からずれた位置の周りでのオブジェクトの回転に見えます。 | これはとても複雑に思えますが、これにはここで目にするより多くのことがあります。上述の[[#Combining Rotations|ダーツ]]に関する議論を思い出して、物理的なダーツを元点がダーツの尾部にありダーツの先端の位置をX,Y,Z要素とする{{LSLG/ja|vector|vector}}に置き換えてみてください。ダーツの尾部回りの回転はダーツの先端をダーツの尾部を中心とした弧に沿って動かします。まさに同様にプリムの中心からずれを表す{{LSLG/ja|vector|vector}}の回転は同じ弧を通りプリムを回転させます。これは{{LSLG/ja|vector|vector}}によりプリムの中心からずれた位置の周りでのオブジェクトの回転に見えます。 | ||
<div id="box"><div style="padding: 0.5em"> | <div id="box"><div style="padding: 0.5em"> | ||
{| cellpadding=0 cellspacing=0 | {| cellpadding=0 cellspacing=0 |
Revision as of 16:47, 3 October 2023
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
There are a few differences between LSL and maths that have little consequences while scripting, but that might puzzle people with prior mathematical knowledge. So we thought it would be good to list them here:
- In LSL, all quaternions are normalized (the dot product of R by R is always 1), and therefore represent ways to rotate objects without changing their size. In maths, generic quaternions might be not normalized, and they represent affinities, i.e. a way to rotate and change the size of objects.
- In LSL, the s term is the fourth member of the rotation: <x, y, z, s>. In maths, the s term, also called "real part", is written as the first coordinate of the quaternion: (s, x, y, z).
- Multiplication is written in reverse order in LSL and in maths. In LSL, you would write R * S, where in maths you would write 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();
便利なスニペット
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
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);
}
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>);
}
// LindaB Helendale
// https://wiki.secondlife.com/wiki/User:LindaB_Helendale/rot2roll_pitch_yaw
定数
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定数