Difference between revisions of "Rotation/ja"

From Second Life Wiki
Jump to navigation Jump to search
m (リンク修正)
 
(4 intermediate revisions by 2 users not shown)
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|テクスチャ}}の項にテクスチャの回転に関しての情報があります。


{{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枚の羽根のついたダーツを持っていたとして、その尾部を原点とし、狙う方向を正のX方向としてX軸上に置き、羽根をZ軸とY軸上に沿わせて、ダーツの軸とその軸が一直線に並んだ状態を回転<0, 0, 0>とします。これをX軸回りに45度、Y軸周りに30度、異なった順番で回転させてみます。


まずX軸回りに45度回転させた後ではダーツはまだX軸方向を向いていて動いていない。羽根は45度、その軸で回転する。次に、Y軸回りの30度回転はXZ平面上でX軸から30度の方向にダーツを動かす。(回転の右手ルールが、Y回りの正方向への小さな回転は位置を下げることを意味するのを覚えていてください)ダーツは回り始めたのと同じ垂直面上で30度下がることになる。しかし、それ自身の長い軸で回るので羽根はもう上下しません。
他のデータ型(例:{{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象限の下にある点へと移動します。羽も回転しながら移動します。
 
明らかに、これは最初の回転とは異なる結果ですが、回転の順序が変更されただけです。


別のやり方として最初にY軸周りに30度回転するとダーツはXZ平面上で回転しますが、X軸上にはダーツがもう無いのに注目してください。そのX軸と空間上のX軸はもう並ぶことはありません。今、X軸での45度回転はダーツの先端をX軸の正領域に沿った軸による30度の円錐に合わせて、その尾部で45度右斜め上へ旋回させる。あなたがX軸から見下ろしていると、それはX軸の下から30度の位置から右斜め上へ、XZ平面の外でXY平面の第一象限の下の位置へ回転するようにダーツの羽根は旋回します。
一定の回転を行うには、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}}を使用します。


一定の回転を行うために、ラジアンでX,Y,Zの角度を要素とする{{LSLG/ja|vector}}(オイラー角と呼ばれる)を作成し、{{LSLG/ja|llEuler2Rot|llEuler2Rot}}関数を使ってそれを'''rotation'''に変換して'''rotation'''値を定義する必要があります。あなたは回転を直接作成することもできます。実数部は回転角の1/2のcosです。ベクトルの部分は正規化した回転軸に回転角の1/2のsinを掛けたものです。
代替方法として、ネイティブな回転を直接作成することもできます。実数部分は回転角の半分の余弦であり、ベクトル部分は回転の軸を正規化し、角度の半分の正弦で乗算したものです。
rotationから{{LSLG/ja|vector|vector}}のオイラー角回転へは{{LSLG/ja|llRot2Euler|llRot2Euler}}を使います。


'''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'''に対して以下のように使うこともできます:
<div id="box"><div style="padding: 0.5em">
<source lang="lsl2">
{| cellpadding=0 cellspacing=0
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 ||= {{LSLG/ja|llEuler2Rot}}(<30, 0,0> * DEG_TO_RAD);||// 度をラジアンに変換してから、{{LSLG/ja|vector|vector}}をrotationのrot30xに代入します。
rotation rot30X = llAxisAngle2Rot(<1, 0, 0>, 30.0*DEG_TO_RAD);  // 度をラジアンに変換してから、ラジアンの値をrot30xに変換します
|-
</source>
|{{LSLG/ja|vector}} vec30X ||= {{LSLG/ja|llRot2Euler}}(rot30X );||// rotationから{{LSLG/ja|vector|vector}}へ逆変換します。(値はラジアンとなるでしょう。)
 
|}
== Differences between math's quaternions and LSL rotations ==
</div></div>
 
数学のクォータニオンとLSLの回転にはいくつかの違いがあり、スクリプトを作成する際にはあまり影響がないかもしれませんが、数学の知識を持つ人々を困惑させる可能性があるため、それらをここにリストアップすることが良いと考えました。:
 
*LSLでは、すべてのクォータニオンは正規化されています('''R'''による'''R'''の内積は常に'''1'''です)。したがって、オブジェクトのサイズを変更せずに回転させる方法を表します。数学では、一般的なクォータニオンは正規化されていない場合があり、オブジェクトのサイズを変更する方法を表します。
* LSLでは、'''s'''の項目は回転の4番目のメンバーです:'''<x, y, z, s>'''。数学では、'''s'''の項目、または「実部」とも呼ばれるものは、クォータニオンの最初の座標として書かれます:'''(s, x, y, z)'''。
* 乗算はLSLと数学では逆の順序で書かれています。LSLでは、'''R * S'''と書きますが、数学では'''S . R'''と書きます。


==オイラーベクトルでの回転の順番==
==オイラーベクトルでの回転の順番==
Line 65: Line 112:
これは、30度の一定の'''rotation'''をオブジェクトの最初の'''rotation'''(myRot)の左側につけることで'''ローカル'''での30度の回転を行います。それは上述のダーツをその長軸の周りに30度にねじる最初の例の最初の操作に似ています。
これは、30度の一定の'''rotation'''をオブジェクトの最初の'''rotation'''(myRot)の左側につけることで'''ローカル'''での30度の回転を行います。それは上述のダーツをその長軸の周りに30度にねじる最初の例の最初の操作に似ています。


<div id="box"><div style="padding: 0.5em">
<source lang="lsl2">
{| cellpadding=0 cellspacing=0
rotation localRot = rot30X * myRot;// ワールドの回転に一定の回転をかけることでローカルの回転を行う。
|-
</source>
|rotation localRot = ||rot30X * myRot;||// ワールドの回転に一定の回転をかけることでローカルの回転を行う。
|}
</div></div>


'''グローバル'''の回転をするためには同じ'''rotation'''を使いますが、順番は逆にしてください。これはダーツが上昇回転してワールドのX軸周りに右に回る2番目の例の2番目の操作に似ています。この場合、既存のrotation(myRot)はグローバルのX軸の周りで30度回転します。
'''グローバル'''の回転をするためには同じ'''rotation'''を使いますが、順番は逆にしてください。これはダーツが上昇回転してワールドのX軸周りに右に回る2番目の例の2番目の操作に似ています。この場合、既存のrotation(myRot)はグローバルのX軸の周りで30度回転します。


<div id="box"><div style="padding: 0.5em">
<source lang="lsl2">
{| cellpadding=0 cellspacing=0
rotation globalRot = myRot * rot30X;// 一定の回転をワールドの回転にかけることでグローバルの回転を行う。
|-
</source>
|rotation globalRot || = myRot * rot30X;||// 一定の回転をワールドの回転にかけることでグローバルの回転を行う。
|}
</div></div>


==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}}よりもさらに効率的ですが中身を覗くのはコストが高いでしょう。


<div id="box"><div style="padding: 0.5em">
<source lang="lsl2">
{| cellpadding=0 cellspacing=0
rotation rot30X     = llEuler2Rot(<30, 0, 0> * DEG_TO_RAD );// rotation定数を作成する
|-
rotation rotCopy     = rot30X;                               // rotCopyに4つのfloat要素全てをコピーします
|rotation rot30X ||= {{LSLG/ja|llEuler2Rot}}(<30, 0,0> * [[#DEG_TO_RAD|DEG_TO_RAD]] );||// rotation定数を作成する
float   X           = rotCopy.x;                           // rotationの個々の要素を出力します
|-
float   Y           = rotCopy.y;
|rotation rotCopy ||= rot30X;||// rotCopyに4つのfloat要素全てをコピーします
float   Z           = rotCopy.z;
|-
float   S           = rotCopy.s;
|float X ||= rotCopy.x;||// rotationの個々の要素を出力します
rotation anotherCopy = <X, Y, Z, S>;                         // 要素から他のrotationを作ります
|-
</source>
|float Y ||= rotCopy.y;||
|-
|float Z ||= rotCopy.z;||
|-
|float S ||= rotCopy.s;||
|-
|rotation anotherCopy ||= <X, Y, Z, S>;||// 要素から他のrotationを作ります
|}
</div></div>
 


ゼロ回転の組み込み定数として[[#ZERO_ROTATION|ZERO_ROTATION]]があり、'''rotation R'''を反転させたい場合は[[#ZERO_ROTATION|ZERO_ROTATION]]を'''R'''で割ります。上記の注意として、これはまずゼロ位置への回転となり、そして除算なので元の'''rotation'''の反対向きへの回転となり、その結果逆回転します。
ゼロ回転の組み込み定数として[[#ZERO_ROTATION|ZERO_ROTATION]]があり、'''rotation R'''を反転させたい場合は[[#ZERO_ROTATION|ZERO_ROTATION]]を'''R'''で割ります。上記の注意として、これはまずゼロ位置への回転となり、そして除算なので元の'''rotation'''の反対向きへの回転となり、その結果逆回転します。
<div id="box"><div style="padding: 0.5em">
<source lang="lsl2">
{| cellpadding=0 cellspacing=0
rotation rot330X       = <-rot30X.x, -rot30X.y, -rot30X.z, rot30X.s>;// 回転の反転 - 注意 要素sの符号は反転していません
|-
rotation another330X   = ZERO_ROTATION / rot30X;                     // 除算による回転の反転、rot330Xと同じ結果となります
|rotation rot330X ||= <-rot30X.x, -rot30X.y, -rot30X.z, rot30X.s>;||// 回転の反転 - 注意 要素sの符号は反転していません
rotation yetanother330X = <rot30X.x, rot30X.y, rot30X.z, -rot30X.s>; // まったく同じではありませんが同じ結果となります。
|-
</source>
|rotation another330X ||= [[#ZERO_ROTATION|ZERO_ROTATION]] / rot30X;||// 除算による回転の反転、rot330Xと同じ結果となります
|-
|rotation yetanother330X ||= <rot30X.x, rot30X.y, rot30X.z, -rot30X.s>;||// まったく同じではありませんが同じ結果となります。
|}
</div></div>


==単一またはルートプリム 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
Line 156: Line 181:
|}
|}
</div></div>
</div></div>
<lsl>
<source lang="lsl2">
//-- same as:
//-- same as:
llSetPrimitiveParams( [PRIM_POSITION, llGetPos() + (gPosOffset - gPosOffset * gRotArc) * llGetRot(),
llSetPrimitiveParams( [PRIM_POSITION, llGetPos() + (gPosOffset - gPosOffset * gRotArc) * llGetRot(),
                       PRIM_ROTATION, gRotArc * llGetRot()] );
                       PRIM_ROTATION, gRotArc * llGetRot()] );
</lsl>
</source>
'''注意:''' これによる移動はプリムを地下や10m以上移動させる結果にもなることを忘れないでください。
'''注意:''' これによる移動はプリムを地下や10m以上移動させる結果にもなることを忘れないでください。


Line 176: Line 201:
|}
|}
</div></div>
</div></div>
<lsl>
<source lang="lsl2">
//-- same as:
//-- same as:
vector correctOffset = llGetPos() + offset * llGetRot();
vector correctOffset = llGetPos() + offset * llGetRot();
</lsl>
</source>
 
=== Position of Object Rotated Around A Relative Point ===
<source lang="lsl2">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</source>
:アプリケーションにおいて、以下の操作が行われています:
<source lang="lsl2">llSetPrimitiveParams( [PRIM_POSITION, llGetPos() + (vPosOffset - vPosOffset * vRotArc) * llGetRot(),
                      PRIM_ROTATION, vRotArc * llGetRot()] );</source>
* 上記の方法では、周回しているオブジェクトは常に中心に対して同じ側面を向いています。回転を保持する代替方法は次の通りです
<source lang="lsl2">llSetPrimitiveParams( [PRIM_POSITION, llGetPos() + (vPosOffset - vPosOffset * vRotArc) * llGetRot()];
vPosOffset = vPosOffset * vRotArc;</source>
'''注意''' これは移動操作ですので、オブジェクトをワールドの外に移動させたり、地下に埋めたり、10メートル以上移動させる場合の問題に注意してください。また、完全な軌道を得るためには、リストされたステップを繰り返す必要があります([[timer/ja|タイマー]]を使用することができます)。
 
'''注意''' これらはルートプリム(または好みに応じた子プリム)に適用されます。子プリムの場合、位置には[[PRIM_POS_LOCAL]]を、回転には[[PRIM_ROT_LOCAL]]または[[llGetLocalRot]]を使用し、回転の中心はルートに対して相対的である必要があります。
 
=== Position of Relative Point Around Rotated Object ===
オブジェクトの現在の向きに対して相対的なポイントを取得するには(rezzorsなどで使用されることがあります)、次のようにします。
<source lang="lsl2">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</source>
:アプリケーションにおいて、以下の操作が行われています:
<source lang="lsl2">llRezAtRoot( "Object", llGetPos() + vPosOffset * llGetRot(), ZERO_VECTOR, ZERO_ROTATION, 0 );</source>
 
==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:
<source lang="lsl2">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>;
}</source>
: '''Note''': 正規化されていない回転を取得するLSLの唯一の方法は、[[llAxes2Rot/ja]]('相互に直交していない入力'または '異なる大きさの入力'を介して)または回転の要素を直接操作することです。他のすべてのll*関数は正規化された回転を返します。前述の例の使用により、有限の精度の制約により、正規化された回転に小さな浮動小数点エラーが導入される可能性があります。


==便利なスニペット==
==便利なスニペット==
<lsl>integer IsRotation(string s)
文字列がRotationか判定
<source lang="lsl2">integer IsRotation(string s)
{
{
     list split = llParseString2List(s, [" "], ["<", ">", ","]);
     list split = llParseString2List(s, [" "], ["<", ">", ","]);
Line 192: Line 275:
     //if the rotation was already broken then the sign flip will have no affect and the values will 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>
     //we cast back to string so we can catch negative zero which allows for support of <0,0,0,0>
}//Strife Onizuka</lsl>
}//Strife Onizuka</source>
 
rotation をRoll Pitch Yawに分割
<source lang="lsl2"> // 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);
}
</source>
Roll Pitch Yawをrotationに変換
<source lang="lsl2"> // 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>);
}
</source>


==定数==
==定数==

Latest revision as of 17:41, 3 October 2023

Rotation

回転 は 4つの浮動小数点値 を含むデータ型です。

各要素は、変数名に .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 RotationsTimmy 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が返されます。回転から軸と角度に戻すには、llRot2AxisllRot2Angleを使用します。

代替方法として、ネイティブな回転を直接作成することもできます。実数部分は回転角の半分の余弦であり、ベクトル部分は回転の軸を正規化し、角度の半分の正弦で乗算したものです。

NOTE:LSLでの角度はラジアンであって度ではありませんが、組み込み定数RAD_TO_DEGDEG_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から成るlistfloatの集まりの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_ROTATIONRで割ります。上記の注意として、これはまずゼロ位置への回転となり、そして除算なので元の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の一部の場合は、それは異なった少し壊れている振る舞いをします。

Getting and setting rotations of prims
関数 地面の (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などに使います)

rotation rotFacing = llGetRot(); // オブジェクトの現在のrotationを得る
vector offset = <0, 0, 1>; // localのZ方向へ正の向きに1mのオフセットを作成する
vector rotatedOffset = offset * rotFacing; // 対応するオブジェクトの回転へオフセットを回転する
vector correctOffset = llGetPos() + rotatedOffset; // ローカルオフセットのregion上の位置を得る
//-- 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定数