Rotation/ja

From Second Life Wiki
Jump to navigation Jump to search

Rotation

LSL のrotation型は3Dでの方位描写に用いられます。(型名を太字で書くように心がけています。)方位あるいは3Dアングルは四方位と呼ばれる数学的オブジェクトによって描写されます。3つが各々面を表し、4つめがオブジェクトが右か左を向いているのかを表す、4つの数字による四方位を思い浮かべることができます。四方位を用いる主な強みは、ジンバルロックの影響を受けないことです。

四方位数学の込み入った内部処理はquaternionを参照しましょう。

listの関数とイベントのrotationとの関連はRotation Synopsisを参照しましょう。

テクスチャのテクスチャの回転時に関しても情報があります。

その他の説明

rotationは<X, Y, Z>の三つの数値で表現する以外にも、オブジェクトの各角度の回転量でも表現します。これはEdit Windowで使用され、例えば人々が見たとおりに作りやすくします。これら3つの数字はvector' であってrotation ではないのですが、同じ情報として表現できるようになっています。

3番目の方法は、手前のポイント、上部のポイント、そして左側のポイントをさす、3つのvectorを用いることです。実際には3つのうち2つが必要とされ、3つめは2つから計測します。

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

フレミングの法則

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

http://en.wikipedia.org/wiki/Right_hand_rule

また、右手を動かさないまま、有効な回転方向の決定にも使います。右手を握り、親指を立てて、好きな軸の方向をさします。人差し指と中指を有効なrotationの方向に向けて曲げます。Rotationは、X、Y、Z軸と回転、傾斜角度、揺れを参照する、よくある特殊な伝達手段です。

Roll Pitch Yaw

Rotationの結合

Rotationを結合するには、掛け算割り算の演算子を用います。rotationへの足し算もしくは引き算の演算子は予期する動作にはならないので、使おうとはしないでください。掛け算の演算子は 方向の加算に、割り算の演算子は方向の引き算に応用されます。つまり、X.s = -X.sのような構成ではないということです。 float以外の型は、floatに変換されます。 non-commutativeが重要です。 rotatonへの変換はRLで重要で、理由は単純です。例えば、4つの羽のあるダーツを持っていたとして、rotation<0,0,0>の尾尻から始めて、有効なX軸方面に照準をつけ、羽をZとY軸のみにし、そしてダーツの軸とダーツ盤の軸を一直線上にします。私達はXを45度前後で、Yを30度前後回転させてやっていますが、それは間違いです。

始めに、X軸を45度回転の後にダーツはX軸上にまだあり、ぶれないまま、長時間軸にそって回転したあと、ダーツは軸を45度にするでしょう。Y軸を30度前後回転しているダーツは、X軸から30度XZ面へ降下するでしょう(rotationでのフレミングの法則は、降下移動したY軸の周囲で小さく有効に回転する、という意味だと思い出しましょう)。ダーツ風の上昇先を30度下げ、飛び始めと同じ高さを飛びますが、ダーツはそう長くは昇降せずに長時間軸に沿って回転されます。

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

明らかにこれは最初のrotationとは異なる結果ですが、rotationの結果が変えられるだけのことです。

ラジアンの構成(オイラーアングルと呼ばれる)でX、Y、Zアングルによるvectorで作成できうる値を定義する必要がある、rotation'の要素を定数のrotationにすることは、llEuler2Rot 関数にて用いるrotationに変換するということです。直に自然なrotationを代わる代わる作ることができます。実際の箇所はrotationのアングルの半分のコサインで、vectorの部分はrotationのアングルの半分のサインとrotationの標準的な角度を掛け算されたものです。llRot2Eulerを使ってrotationからオイラーアングルの vectorにしましょう。

NOTE:LSLのアングルはラジアンであって角度ではありませんが、ビルトイン定数RAD_TO_DEGDEG_TO_RADを使うことで、簡単に変換できます。X軸周りの30度のrotationのために、あなたはこう使うこともできます。

rotation rot30X = llEuler2Rot(<30, 0,0> * DEG_TO_RAD); // vectorをrotationのrot30Xに代入して、角度からラジアンに変換します。
vector vec30X = llRot2Euler(rot30X ); // rotationからvectorへ逆変換します。(値はラジアンとなるでしょう。)

Order of rotation for Euler Vectors

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 vector using the Z, Y, X rotation order, then use the llEuler2Rot function to get the rotation for use in combining rotations or applying the rotation to the object.

Local vs Global (World) rotations

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.

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.

In LSL, the difference between doing a local or global rotation is the order the rotations are evaluated in the statement.

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 localRot = rot30X * myRot; // do a local rotation by multiplying a constant rotation by a world rotation

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 globalRot = myRot * rot30X; // do a global rotation by multiplying a world rotation by a constant rotation

Another way to think about combining rotations

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.

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.

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.

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.

Using Rotations

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 float values, each rotation stores four of them and a list consisting of rotation is more efficient than a list consisting of floats, but there is overhead in unpacking them.

rotation rot30X = llEuler2Rot(<30, 0,0> * DEG_TO_RAD ); // Create a rotation constant
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;
float Z = rotCopy.z;
float S = rotCopy.s;
rotation anotherCopy = <X, Y, Z, S>; // Make another rotation out of the components


There is a built in constant for a zero rotation ZERO_ROTATION which you can use directly or, if you need to invert a rotation R, divide 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.

rotation rot330X = <-rot30X.x, -rot30X.y, -rot30X.z, rot30X.s>; // invert a rotation - NOTE the s component isn't negated
rotation another330X = ZERO_ROTATION / rot30X; // invert a rotation by division, same result as rot330X
rotation yetanother330X = <rot30X.x, rot30X.y, rot30X.z, -rot30X.s>; // not literally the same but works the same.

Single or Root Prims vs Linked Prims vs Attachments

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. There are generally three coordinate systems a prim can be in: all alone, part of a linkset, or part of an attachment. When a prim is alone, i.e., not part of a linkset, it acts like a root prim; when it is part of an attachment, it acts differently and is a bit broken.

Getting and setting rotations of prims
Function Ground (rez'ed) Prims Attached Prims
Root Children Root Children
llGetRot
llGPP:PRIM_ROTATION
llGetObjectDetails
global rotation of prim global rotation of prim global rotation of avatar global rotation of avatar * global rotation of prim (Not Useful)
llGetLocalRot
llGPP:PRIM_ROT_LOCAL
global rotation of prim rotation of prim relative to root prim rotation of attachment relative to attach point rotation of prim relative to root prim
llGetRootRotation global rotation of prim global rotation of root prim global rotation of avatar global rotation of avatar
llSetRot*
llSPP:PRIM_ROTATION*
set global rotation complicated, see llSetRot set rotation relative to attach point set rotation to root attachment rotation * new_rot.
llSetLocalRot*
llSPP:PRIM_ROT_LOCAL*
set global rotation set rotation of prim relative to root prim set rotation relative to attach point set rotation of prim relative to root prim
llTargetOmega
ll[GS]PP:PRIM_OMEGA
spin linkset around prim's location spin prim around its location spin linkset around attach point spin prim around its location
Physical objects which are not children in a linkset will not respond to setting rotations.
†  For non-Physical objects llTargetOmega is executed on the client side, providing a simple low lag method to do smooth continuous rotation.

Rotating Vectors

In LSL, rotating a 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.

This sounds very complex, but there is much less here than meets the eye. Remember from the above discussion of rotating the dart, and replace the physical dart with a 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 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 vector from the center of the prim.

rotation rot30X = llEuler2Rot(<30, 0,0> * DEG_TO_RAD ); // create a rotation constant, 30 degrees around the X axis
vector offset = <0, 1, 0>; // create an offset one meter in the global positive Y direction
vector rotatedOffset = offset * rot30X; // rotate the offset to get the motion caused by the rotations
vector newPos = llGetPos() + rotatedOffset; // move the prim position by the rotated offset amount

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.

Constants

ZERO_ROTATION

ZERO_ROTATION = <0.0, 0.0, 0.0, 1.0>;
A rotation constant representing a Euler angle of <0.0, 0.0, 0.0>.

DEG_TO_RAD

DEG_TO_RAD = 0.01745329238f;
A float constant that when multiplied by an angle in degrees gives the angle in radians.

RAD_TO_DEG

RAD_TO_DEG = 57.29578f;
A float constant when multiplied by an angle in radians gives the angle in degrees.