Difference between revisions of "Rotation/ja"

From Second Life Wiki
Jump to navigation Jump to search
(New page: {{Multi-lang}} {{LSL Header/ja}}{{RightToc}} =Rotation= LSL の'''rotation'''型は3Dでの方位描写に用いられます。(型名を'''太字'''で書くように心がけていま...)
 
 
(24 intermediate revisions by 7 users not shown)
Line 1: Line 1:
{{Multi-lang}}
{{Multi-lang}}
{{LSL Header/ja}}{{RightToc}}
{{LSL Header/ja}}{{RightToc}}
=Rotation=
==Rotation==
LSL の'''rotation'''型は3Dでの方位描写に用いられます。(型名を'''太字'''で書くように心がけています。)方位あるいは3Dアングルは{{LSLG|quaternion/ja|四方位}}と呼ばれる数学的オブジェクトによって描写されます。3つが各々面を表し、4つめがオブジェクトが右か左を向いているのかを表す、4つの数字による四方位を思い浮かべることができます。四方位を用いる主な強みは、[http://en.wikipedia.org/wiki/Gimbal_Lock ジンバルロック]の影響を受けないことです。
[[rotation/ja|回転]] は 4つの[[float/ja|浮動小数点値]] を含む{{LSLGC|Types|データ型}}です。


四方位数学の込み入った内部処理は{{LSLG|quaternion/ja|quaternion}}を参照しましょう。
各要素は、変数名に <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>


listの関数とイベントのrotationとの関連は{{LSLG|Rotation Synopsis/ja|Rotation Synopsis}}を参照しましょう。
LSL の'''rotation'''型は3Dでの方位を表すのに用いられます。(型名を'''太字'''で書くように心がけています。)方位あるいは3Dアングルは{{LSLG/ja|quaternion|クォータニオン}}と呼ばれる数学的オブジェクトによって表されます。クォータニオンは4つの数値から成ると考えることができ、3つがオブジェクトの向いている方向を表し、4つめがその方向の周りでのオブジェクトの右か左への傾きを表します。クォータニオンを用いる主な利点は、[http://en.wikipedia.org/wiki/Gimbal_Lock ジンバルロック]の影響を受けないことです。
クォータニオン数学の込み入った内部処理は{{LSLG/ja|quaternion|クォータニオン}}を参照してください。
rotationに関連する関数とイベントの一覧は{{LSLG/ja|Rotation Synopsis|Rotation Synopsis}}を参照してください。
{{LSLG/ja|texture|テクスチャ}}の項にテクスチャの回転に関しての情報があります。


{{LSLG|texture/ja|テクスチャ}}のテクスチャの回転時に関しても情報があります。
回転はしばしば非常に混乱するトピックと見なされ、スクリプターは試行錯誤して正確な結果を得ることがあります。この混乱の理由は次のとおりです:
* 誰もが本当の意味で[[quaternion/ja|クォータニオン]] が何であり、それをどのように考えるべきかを正確に知らない(完全には真実ではありませんが、脳は4つの幾何学的次元で考えることが得意ではありません)。
* 実際には異なるタイプのベクトル('dir'、'vec'、'pos')がいくつかあり、それぞれ異なる方法で操作する必要があります。
* 移動と回転を適用する順序はケースによって異なる場合があります。
* 適用された回転と座標系間の回転 'オフセット' の違いについて混乱があります。
したがって、回転をマスターするには、変数のための良い命名システムを使用することが不可欠です。このようなシステムは、[[User:Timmy_Foxclaw/About_Coordinate_Systems_and_Rotations|About Coordinate Systems and Rotations]] で [[User:Timmy_Foxclaw|Timmy Foxclaw]]によって詳しく説明されています。


==その他の説明==
==その他の表現==
rotationは<X, Y, Z>の三つの数値で表現する以外にも、オブジェクトの各角度の回転量でも表現します。これはEdit Windowで使用され、例えば人々が見たとおりに作りやすくします。これら3つの数字は''vector''' であって'''rotation''' ではないのですが、同じ情報として表現できるようになっています。
===Euler vector===
3D角度を表す別の方法は、<X、Y、Z> という3つの数値を使用することです。これらの数値は、オブジェクトが各軸を中心に回転する量を表します。たとえば、これは編集ウィンドウで使用され、一般的には人々が視覚化しやすいです。編集ウィンドウでの回転 <x、y、z> 数値を調整し、オブジェクトの挙動を確認するのは簡単です。編集ウィンドウでは、数値は度数で表されます。つまり、直角は90度です。


3番目の方法は、手前のポイント、上部のポイント、そして左側のポイントをさす、3つのvectorを用いることです。実際には3つのうち2つが必要とされ、3つめは2つから計測します。
LSLでは、これらの3つの角度は度数ではなく{{LSLG/ja|radians|ラジアン}}で表されます。つまり、直角はPI/2です。ラジアンは非常に幅広い度数のようなものです。
これらの3つの数値は、回転型ではなくベクトル型であり、同じ情報を表すことができます。これは3D角度の ''オイラー'' 表現と呼ばれます。'''LSLでは、zの周りの回転が最初に行われ、次にyの周り、最後にxの周りが行われます'''。


よくある事象として、4つの数字を結合することで成り立つ'''rotation'''は分かりやすいけど、初心者が理解するには難しいというものです。幸いにも実際に内部で''rotaton''にて表現することが必要になるのは早々無く、簡単に変換をやり取りする関数があります。


==フレミングの法則==
LSLの全rotationは'''フレミングの法則'''に沿っています。右手の、人差し指は有効なX軸の方向をさします。中指はY軸を
さすことでしょう。親指はZ軸をさします。オブジェクトを編集するとき、三色の軸の矢印はそれぞれ有効な軸(X: red, Y: green, Z: blue) を示します。


http://en.wikipedia.org/wiki/Right_hand_rule
回転を表す他の手段は、<X,Y,Z>の3つからなる数値を、オブジェクトの各軸回りの回転量({{LSLG/ja|radians|ラジアン}})として用いることです。これは例えばエディットウィンドウで用いられていて、人々が思い描くのがわりと容易です。この3つの数値は'''vector'''であって'''rotation'''型では無いことに注意してください。ですがそれらは同じ情報を表すことができます。これは回転のオイラー角表現と呼ばれます。


また、右手を動かさないまま、有効な回転方向の決定にも使います。右手を握り、親指を立てて、好きな軸の方向をさします。人差し指と中指を有効なrotationの方向に向けて曲げます。Rotationは、X、Y、Z軸と回転、傾斜角度、揺れを参照する、よくある特殊な伝達手段です。
3番目の方法は、前方、上方、そして左側を指す3つのvectorを用いることです。実際には3つのうち2つのみが必要で、3つめの値は2つから求めます。


[http://en.wikipedia.org/wiki/Tait-Bryan_angles Roll Pitch Yaw]
回転を合成できるなどのもっともな理由があるので、4つの数値からなる'''rotation'''は優れているのですが、初心者が理解するのはより難しいです。幸いにも、実際の''rotation''の内部表現で何かすることはめったに必要ありませんし、また簡単にこれらの間を変換する関数があります。


==Rotationの結合==
===軸に角度を加算===
'''Rotation'''を結合するには、'''掛け算'''と'''割り算'''の演算子を用います。'''rotation'''への足し算もしくは引き算の演算子は予期する動作にはならないので、使おうとはしないでください。'''掛け算'''の演算子は
この方法では、地球が回転する軸を定義し、その軸と回転軸周りの回転量を定義して、'''rotation''' を与えます。
方向の加算に、'''割り算'''の演算子は方向の引き算に応用されます。つまり、X.s = -X.sのような構成ではないということです。
{{LSLG|float/ja|float}}以外の型は、floatに変換されます。
[http://en.wikipedia.org/wiki/Commutative 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度下げ、飛び始めと同じ高さを飛びますが、ダーツはそう長くは昇降せずに長時間軸に沿って回転されます。
例えば、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'''を定義します。


ほかの方法を取るとするならば、最初にY軸を30度回転させて、ダーツがXZ面に回転降下するのでしょうが、X軸上にはそう長くはいないことに注目します。ダーツのX軸とダーツ板が一直線上にはならないからです。今X軸周りを45度回転するダーツは、ダーツの尾尻を中心にし、40度右上がり向きに、長時間有効なダーツ板のX軸が30度の円錐上にあるポイントへ従います。X軸へと降下しているように見えたなら、ダーツはX軸の30度以下のポイントから旋回し、右上がりにXZ面上から出て、XY面上の最初の四分儀以下のポイントへ、ダーツは回転して進みます。
軸に角度を加算も四つの数値を使用しますが、"正規化"される必要はありません。


明らかにこれは最初のrotationとは異なる結果ですが、rotationの結果が変えられるだけのことです。
===FWD, LEFT, UP===
同じ3Dの角度を表現する別の方法は、前方が何を指しているか(fwd)、上部が何を指しているか(up)、そして左側が何を指しているか(left)を示す3つのベクトルを使用することです。 実際には、3つのうちの2つだけが必要です。 なぜなら、2つのベクトルを使用すると、残りの1つを決定できるからです。


ラジアンの構成(オイラーアングルと呼ばれる)でX、Y、Zアングルによる{{LSLG|vector}}で作成できうる値を定義する必要がある、''rotation'''の要素を定数のrotationにすることは、{{LSLG|llEuler2Rot/ja|llEuler2Rot}} 関数にて用いる'''rotation'''に変換するということです。直に自然なrotationを代わる代わる作ることができます。実際の箇所はrotationのアングルの半分のコサインで、vectorの部分はrotationのアングルの半分のサインとrotationの標準的な角度を掛け算されたものです。{{LSLG|llRot2Euler/ja|llRot2Euler}}を使ってrotationからオイラーアングルの {{LSLG|vector/ja|vector}}にしましょう。
良い理由があるため、例えば'''rotation'''を簡単に組み合わせることができるように、四つの数値バージョンであるクォータニオンの'''rotation'''がより良いですが、初心者にとって理解が難しいかもしれません。 幸いなことに、'''rotation'''の実際の内部表現で何かを行う必要があることはほとんどなく、3つのLSLタイプと度とラジアンの間を簡単に変換するための関数が存在します。


'''NOTE:''' angles in LSL are in radians, not degrees, but you can easily convert by using the built-in constants [[#RAD_TO_DEG|RAD_TO_DEG]] and [[#DEG_TO_RAD|DEG_TO_RAD]]. For a 30 degree '''rotation''' around the X axis you might use:
==右手ルール==
LSLでは全ての回転が'''右手ルール'''に沿って行われています。右手で人差し指をx軸の正方向へ伸ばしてみてください。中指を人差し指から直角に伸ばすと、y軸の正方向を指します。そして親指を両指から直角に伸ばすとz軸の正方向を指します。あなたがオブジェクトを編集するとき、3色の軸の矢印は各軸(X: 赤, Y: 緑, Z: 青)の正方向を示します。


<div id="box"><div style="padding: 0.5em">
http://ja.wikipedia.org/wiki/右手の法則
{| cellpadding=0 cellspacing=0
 
|-
さて、右手はまだ戻さないでください。正方向の回転の向きを求めるという別の使い道があります。右手を握り、親指を立てて好きな軸の正方向を指します。あなたの他の指は正方向の回転の向きに曲がります。x,y,z軸周りの回転は特に乗り物において、しばしばロール、ピッチ、ヨーとして示されます。
|rotation rot30X ||= {{LSLG|llEuler2Rot}}(<30, 0,0> * DEG_TO_RAD);||// convert the degrees to radians, then convert that {{LSLG|vector}} into a rotation, rot30x
 
|-
http://ja.wikipedia.org/wiki/ローリング ・ http://ja.wikipedia.org/wiki/ピッチング ・ http://ja.wikipedia.org/wiki/ヨーイング
|{{LSLG|vector}} vec30X ||= {{LSLG|llRot2Euler}}(rot30X );||// convert the rotation back to a {{LSLG|vector}} (the values will be in radians)
 
|}
==Rotationの合成==
</div></div>
考えてみましょう。2つの回転があると仮定しましょう。''r1'' は左に90度回転し、''r2'' は右に30度回転します。(どの回転でも構いません;これは単なる例です。)
* 演算子を使用して ''r1'' と r2 を結合して、''r3'' を作成できます。実際にはそれらを「掛け算」するのではなく、それらを「合成」します。
<source lang="lsl2">
rotation r3 = r1 * r2;
</source>
 
'''Rotation'''を合成するには、'''掛け算'''と'''割り算'''の演算子を用います。'''rotation'''への足し算もしくは引き算の演算子は予期する動作にはならないので、使おうとはしないでください。'''掛け算'''の演算子は
正方向の回転に、'''割り算'''の演算子は負方向の回転に用いられます。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'''に対して以下のように使うこともできます:
<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 ==
 
数学のクォータニオンと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つ以上の軸で同時に回転させたい場合、現在の''オイラー''{{LSLG/ja|vector|vector}}をZ, Y, X回転の順に決定し、回転の合成またはオブジェクトへ回転を適用させるための'''rotation'''を得るために{{LSLG/ja|llEuler2Rot|llEuler2Rot}}関数を使います。
 
==ローカル vs グローバル(ワールド)rotation==
 
ワールドの'''rotation'''とオブジェクト自体のローカルの'''rotation'''とを区別することは重要です。エディタでは、あなたは一方からもう片方へと切り替えることができます。 スクリプトではあなたは要求する振る舞いを得るために一方から他方へと変換しなければなりません。
 
'''ローカル'''の回転は、オブジェクトがワールド内でどんな回転をしているかに関わらないオブジェクト自身の前後、左右、上下に当てはめられた軸周りでの回転です。'''グローバル'''の回転は南北、東西、上下のワールドの軸周りでの回転です。あなたはプリムの回転の違いを見ることができ、編集やローカルとグローバルの軸の設定を色のついた矢印が変わるの注意しながら変更することができます。
 
LSLでは'''ローカル'''と'''グローバル'''の回転の違いは、ステートメント内で'''rotation'''が評価される順番の違いとなります。
 
これは、30度の一定の'''rotation'''をオブジェクトの最初の'''rotation'''(myRot)の左側につけることで'''ローカル'''での30度の回転を行います。それは上述のダーツをその長軸の周りに30度にねじる最初の例の最初の操作に似ています。
 
<source lang="lsl2">
rotation localRot = rot30X * myRot;// ワールドの回転に一定の回転をかけることでローカルの回転を行う。
</source>


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


From the above discussion, it's clear that when dealing with rotations around more than one axis, the order they are done in is critical. In the ''Euler'' discussion above this was kind of glossed over a bit, the individual rotations around the three axis define an overall ''rotation'', but that begs the question: What axis order are the rotations done in? The answer is '''Z, Y, X''' in global coordinates. If you are trying to rotate an object around more than one axis at a time using the ''Euler'' representation, determine the correct ''Euler'' {{LSLG|vector}} using the Z, Y, X rotation order, then use the {{LSLG|llEuler2Rot}} function to get the '''rotation''' for use in combining rotations or applying the rotation to the object.
<source lang="lsl2">
rotation globalRot = myRot * rot30X;// 一定の回転をワールドの回転にかけることでグローバルの回転を行う。
</source>


== Local vs Global (World) rotations ==
==rotationの結合について考える他の方法==


It is important to distinguish between the '''rotation''' relative to the world, and the '''rotation''' relative to the local object itself.  In the editor, you can switch back and forth from one to the other.  In a script, you must convert from one to the other to get the desired behavior.
あなたは'''ローカル'''と'''グローバル'''の違いについて、括弧以外は左から右へと評価されるという'''rotation'''の評価順序から考えてみたいかもしれません。


'''Local''' rotations are ones done around the axes embedded in the object itself forward/back, left/right, up/down, irrespective of how the object is rotated in the world. '''Global''' rotations are ones done around the world axes, North/South, East/West, Higher/Lower. You can see the difference by rotating a prim, then edit it and change the axes settings between local and global, notice how the colored axes arrows change.
localRotの場合は、<0, 0, 0>から始まって、rot30Xが最初に行われ、ワールドのX軸回りにプリムが回転し、回転の始まる時点からローカルとグローバルの軸はオブジェクトのローカルのX軸に沿った同一の回転をします。
そして、2つめの'''rotation'''であるmyRotは、プリムをオリジナルのrotationで回転させましたが、さらにX軸の回転が焼きつきます。
これは、プリムの回転がそのX軸に沿ってYとZの'''rotation'''が変わらないローカル回転のようになります。


In LSL, the difference between doing a '''local''' or '''global''' rotation is the order the '''rotations''' are evaluated in the statement.
globalRotの場合は、再び<0, 0, 0>から始まって、まずオブジェクトがオリジナルのrotation(myRot)で回転しますが、オブジェクトの軸とワールドの軸はもはや一致しません!そして、2つめの'''rotation'''であるrot30xは、まさにローカルの場合と同様に、オブジェクトをワールドのX軸回りに30度回転しますが、その効果はオブジェクトをワールドのX軸に沿って円錐を回転させます。オブジェクトのX軸とワールドのX軸はこの時点では一致しません。プリムはワールドのX軸の沿って30度回転するように見えます。そのため'''global''' rotationのようになります。


This does a '''local''' 30 degree rotation by putting the constant 30 degree '''rotation''' to the left of the object's starting '''rotation''' (myRot). It is like the first operation in the first example above, just twisting the dart 30 degrees around its own long axis.
'''rotation'''の割り算は、反対方向のrotationにする効果があり、330度のrotationによる掛け算は、30度の'''rotation'''による割り算と同じです。


<div id="box"><div style="padding: 0.5em">
==rotationを使う==
{| cellpadding=0 cellspacing=0
|-
|rotation localRot = ||rot30X * myRot;||// do a local rotation by multiplying a constant rotation by a world rotation
|}
</div></div>


To do a '''global''' rotation, use the same '''rotation''' values, but in the opposite order. This is like the second operation in the second example, the dart rotating up and to the right around the world X axis. In this case, the existing rotation (myRot) is rotated 30 degrees around the global X axis.
'''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 globalRot || = myRot * rot30X;||// do a global rotation by multiplying a world rotation by a constant rotation
float    X          = rotCopy.x;                            //  rotationの個々の要素を出力します
|}
float    Y          = rotCopy.y;
</div></div>
float    Z          = rotCopy.z;
float    S          = rotCopy.s;
rotation anotherCopy = <X, Y, Z, S>;                        // 要素から他のrotationを作ります
</source>


== Another way to think about combining rotations ==
ゼロ回転の組み込み定数として[[#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>


You may want to think about this '''local''' vs '''global''' difference by considering that '''rotations''' are done in evaluation order, that is left to right except for parenthesized expressions.
==単一またはルートプリム vs リンクプリム vs アタッチメント ==


In the localRot case, what happened was that starting from <0, 0, 0>, the rot30X was done first, rotating the prim around the world X axis, but since when it's unrotated, the local and global axes are identical it has the effect of doing the rotation around the object's local X axis. Then the second '''rotation''' myRot was done which rotated the prim to its original rotation, but now with the additional X axis rotation baked in. What this looks like is that the prim rotated in place, around its own X axis, with the Y and Z rotations unchanged, a '''local''' rotation.
単一またはリンクプリムの回転について語る理由として、どんなビークル全体の回転があっても対応してドアが動くという望ましい動きするビークルのドアなどのためです。グローバルな回転でこれを行える間はそれはとても退屈でしょう。通常、プリムが扱える座標系には単独、{{LSLG/ja|linkset}}の一部、{{LSLG/ja|attachment}}の一部の3つがあります。プリム単独のとき、すなわち{{LSLG/ja|linkset}}ではない場合は、ルートプリムのように振舞います; {{LSLG/ja|attachment}}の一部の場合は、それは異なった少し壊れている振る舞いをします。


In the globalRot case, again starting from <0, 0, 0>, first the object is rotated to its original rotation (myRot), but now the object's axes and the world's axes are no longer aligned! So, the second '''rotation''' rot30x does exactly what it did in the local case, rotates the object 30 degrees around the world X axis, but the effect is to rotate the object through a cone around the world X axis since the object's X axis and the world's X axis aren't the same this time. What this looks like is that the prim pivoted 30 degrees around the world X axis, hence a '''global''' rotation.
{{LSLRotGetSet/ja}}


'''Division''' of '''rotations''' has the effect of doing the rotation in the opposite direction, multiplying by a 330 degree '''rotation''' is the same as dividing by a 30 degree '''rotation'''.
==Vectorの回転==


==Using Rotations ==
LSLでは{{LSLG/ja|vector|vector}}を回転させるのは回転の中心がオブジェクトの中心ではないオブジェクトを弧や円状に動かしたいときにとても役立ちます。


You can access the individual components of a '''rotation''' '''R''' by '''R.x, R.y, R.z, & R.s''' ('''not''' R.w).  The scalar part R.s is the cosine of half the angle of rotation.  The vector part (R.x,R.y,R.z) is the product of the normalized axis of rotation and the sine of half the angle of rotation.  You can generate an inverse '''rotation''' by negating the x,y,z members (or by making the s value negative). As an aside, you can also use a '''rotation''' just as a repository of {{LSLG|float}} values, each '''rotation''' stores four of them and a {{LSLG|list}} consisting of '''rotation''' is more efficient than a {{LSLG|list}} consisting of {{LSLG|float}}s, but there is overhead in unpacking them.
これはとても複雑に思えますが、これにはここで目にするより多くのことがあります。上述の[[#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
|-
|-
|rotation rot30X ||= {{LSLG|llEuler2Rot}}(<30, 0,0> * [[#DEG_TO_RAD|DEG_TO_RAD]] );||// Create a rotation constant
|rotation rot6X ||= {{LSLG/ja|llEuler2Rot}}(<30, 0, 0> * [[#DEG_TO_RAD|DEG_TO_RAD]] );||// [[Viewer_coordinate_frames/ja#Local|local]]のX軸回りに30度するrotationの定数を作成する
|-
|rotation rotCopy ||= rot30X;||// Just copy it into rotCopy, it copies all 4 float components
|-
|float X ||= rotCopy.x;||// Get out the individual components of the rotation
|-
|-
|float Y ||= rotCopy.y;||
|vector offset ||= <0, 1, 0>;||// [[Viewer_coordinate_frames/ja#Local|local]]のY方向へ正の向きで1mのオフセットを作成する
|-
|-
|float Z ||= rotCopy.z;||
|vector rotatedOffset || = offset * rot6X;||// rotationによる動きを得るためにオフセットを回転する
|-
|-
|float S ||= rotCopy.s;||
|vector newPos || = {{LSLG/ja|llGetPos}}() + (offset - rotatedOffset) * {{LSLG/ja|llGetRot}}();||// 回転したオフセット分だけプリムの位置を動かします
|-
|-
|rotation anotherCopy ||= <X, Y, Z, S>;||// Make another rotation out of the components
|rotation newRot|| = rot6X * {{LSLG/ja|llGetRot}}();||// オフセット点を向くために回転を変更します
|}
|}
</div></div>
</div></div>
<source lang="lsl2">
//-- same as:
llSetPrimitiveParams( [PRIM_POSITION, llGetPos() + (gPosOffset - gPosOffset * gRotArc) * llGetRot(),
                      PRIM_ROTATION, gRotArc * llGetRot()] );
</source>
'''注意:''' これによる移動はプリムを地下や10m以上移動させる結果にもなることを忘れないでください。


 
オブジェクトの現在の向きに対応した点を得る(rezzorsなどに使います)
There is a built in constant for a zero '''rotation''' [[#ZERO_ROTATION|ZERO_ROTATION]] which you can use directly or, if you need to invert a '''rotation R''', divide [[#ZERO_ROTATION|ZERO_ROTATION]] by '''R'''. As a reminder from above, this works by first rotating to the zero position, then because it is a divide, rotating in the opposite sense to the original  '''rotation''', thereby doing the inverse rotation.
<div id="box"><div style="padding: 0.5em">
<div id="box"><div style="padding: 0.5em">
{| cellpadding=0 cellspacing=0
{| cellpadding=0 cellspacing=0
|-
|-
|rotation rot330X ||= <-rot30X.x, -rot30X.y, -rot30X.z, rot30X.s>;||// invert a rotation - NOTE the s component isn't negated
|rotation rotFacing ||= {{LSLG/ja|llGetRot}}();||// オブジェクトの現在のrotationを得る
|-
|vector offset ||= <0, 0, 1>;||// [[Viewer_coordinate_frames/ja#Local|local]]のZ方向へ正の向きに1mのオフセットを作成する
|-
|-
|rotation another330X ||= [[#ZERO_ROTATION|ZERO_ROTATION]] / rot30X;||// invert a rotation by  division, same result as rot330X
|vector rotatedOffset || = offset * rotFacing;||// 対応するオブジェクトの回転へオフセットを回転する
|-
|-
|rotation yetanother330X ||= <rot30X.x, rot30X.y, rot30X.z, -rot30X.s>;||// not literally the same but works the same.
|vector correctOffset || = {{LSLG/ja|llGetPos}}() + rotatedOffset;||// ローカルオフセットの[[Viewer_coordinate_frames/ja#Region|region]]上の位置を得る
|}
|}
</div></div>
</div></div>
<source lang="lsl2">
//-- same as:
vector correctOffset = llGetPos() + offset * llGetRot();
</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


==Single or Root Prims vs Linked Prims vs Attachments ==
vector  vPosOffsetDiff = vPosOffset - vPosRotOffset;
//-- gets the local difference between the current offset and the rotated one


The reason for talking about single or linked prim rotations is that for things like doors on vehicles, the desired motion is to move the door relative to the vehicle, no matter what the rotation of the overall vehicle is. While possible to do this with global rotations, it would quickly grow tedious.
vector  vPosRotDiff    = vPosOffsetDiff * llGetRot();
There are generally three coordinate systems a prim can be in: all alone, part of a {{LSLG|linkset}}, or part of an {{LSLG|attachment}}. When a prim is alone, i.e., not part of a {{LSLG|linkset}}, it acts like a root prim; when it is part of an {{LSLG|attachment}}, it acts differently and is a bit broken.
//-- rotates the difference in the offsets to be relative to the global rotation.


{{LSLRotGetSet}}
vector  vPosNew        = llGetPos() + vPosRotDiff;
//-- finds the prims new position by adding the rotated offset difference


==Rotating Vectors ==
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|タイマー]]を使用することができます)。


In LSL, rotating a {{LSLG|vector}} is very useful if you want to move an object in an arc or circle when the center of rotation isn't the center of the object.
'''注意''' これらはルートプリム(または好みに応じた子プリム)に適用されます。子プリムの場合、位置には[[PRIM_POS_LOCAL]]を、回転には[[PRIM_ROT_LOCAL]]または[[llGetLocalRot]]を使用し、回転の中心はルートに対して相対的である必要があります。


This sounds very complex, but there is much less here than meets the eye. Remember from the above discussion of rotating the [[#Combining Rotations|dart]], and replace the physical dart with a {{LSLG|vector}} whose origin is the tail of the dart, and whose components in X, Y, and Z describe the position of the tip of the dart. Rotating the dart around its tail moves the tip of the dart through and arc whose center of rotation is the tail of the dart. In exactly the same way, rotating a {{LSLG|vector}} which represents an offset from the center of a prim rotates the prim through the same arc. What this looks like is the object rotates around a position offset by the {{LSLG|vector}} from the center of the prim.
=== Position of Relative Point Around Rotated Object ===
オブジェクトの現在の向きに対して相対的なポイントを取得するには(rezzorsなどで使用されることがあります)、次のようにします。
<div id="box"><div style="padding: 0.5em">
<source lang="lsl2">vector   vPosOffset    = <0.0, 0.0, 1.0>;
{| cellpadding=0 cellspacing=0
//-- creates an offset one meter in the positive Z direction.
|-
 
|rotation rot30X ||= {{LSLG|llEuler2Rot}}(<30, 0,0> * [[#DEG_TO_RAD|DEG_TO_RAD]] );||// create a rotation constant, 30 degrees around the X axis
vector  vPosRotOffset  = vPosOffset * llGetRot();
|-
//-- rotate the offset to be relative to objects rotation
|vector offset ||= <0, 1, 0>;||// create an offset one meter in the global positive Y direction
 
|-
vector   vPosOffsetIsAt = llGetPos() + vPosRotOffset;
|vector rotatedOffset || = offset * rot30X;||// rotate the offset to get the motion caused by the rotations
//-- get the region position of the rotated offset</source>
|-
:アプリケーションにおいて、以下の操作が行われています:
|vector newPos || = {{LSLG|llGetPos}}() + rotatedOffset;||// move the prim position by the rotated offset amount
<source lang="lsl2">llRezAtRoot( "Object", llGetPos() + vPosOffset * llGetRot(), ZERO_VECTOR, ZERO_ROTATION, 0 );</source>
|}
 
</div></div>
==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*関数は正規化された回転を返します。前述の例の使用により、有限の精度の制約により、正規化された回転に小さな浮動小数点エラーが導入される可能性があります。
 
==便利なスニペット==
文字列がRotationか判定
<source lang="lsl2">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</source>


'''Nota Bene:''' Doing this is a move, so don't forget about issues of moving a prim off world, below ground, more than 10 meters etc.
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>


== Constants ==
==定数==
=== [[ZERO_ROTATION]] ===
=== [[ZERO_ROTATION/ja|ZERO_ROTATION]] ===
ZERO_ROTATION = <0.0, 0.0, 0.0, 1.0>;<br/>
ZERO_ROTATION = <0.0, 0.0, 0.0, 1.0>;<br/>
A rotation constant representing a Euler angle of <0.0, 0.0, 0.0>.
オイラー角の<0.0, 0.0, 0.0>に相当するrotation定数
 
=== [[DEG_TO_RAD/ja|DEG_TO_RAD]] ===
=== [[DEG_TO_RAD]] ===
DEG_TO_RAD = 0.01745329238f;<br/>
DEG_TO_RAD = 0.01745329238f;<br/>
A float constant that when multiplied by an angle in degrees gives the angle in radians.
角度(°)から乗算でラジアン角を得るときのfloat定数


=== [[RAD_TO_DEG]] ===
=== [[RAD_TO_DEG/ja|RAD_TO_DEG]] ===
RAD_TO_DEG = 57.29578f;<br/>
RAD_TO_DEG = 57.29578f;<br/>
A float constant when multiplied by an angle in radians gives the angle in degrees.
ラジアン角から乗算で角度(°)を得るときのfloat定数
 


[[Category:LSL_Types|Rotation]][[Category:LSL_Math]][[Category:LSL_Math/3D]][[Category:LSL_Constants]]
{{LSLC/ja|Types}}
{{LSLC/ja|Math}}
{{LSLC/ja|Math/3D}}

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定数