Difference between revisions of "Rotation"
Althaea Xeno (talk | contribs) m (→rotation) |
(→rotation: reworded intro) |
||
Line 2: | Line 2: | ||
== rotation == | == rotation == | ||
The LSL type used to hold a 3D angle is a '''rotation''' | The LSL type used to hold a 3D angle is called a '''rotation'''. | ||
In LSL, a 3D angle is represented by a {{LSLG|quaternion}}. You can think of a quaternion as three numbers that represent the direction an object is facing, and a fourth number that represents the object's orientation around that direction. The main advantage of using these | |||
quaternions is that they are not susceptible to [http://en.wikipedia.org/wiki/Gimbal_Lock gimbal lock]. | |||
Another way to represent a rotation is using three numbers, <X, Y, Z>, which represent the rotation around each axis. This is used in the Edit window. In LSL, these three numbers are called the Euler representation of a rotation. For good reasons, the four number version is better, though harder for a beginner to grasp. There are functions for converting easily back and forth. | |||
The rest of this article is | A third way is to use three vectors. What is the front pointing at, what is the top pointing at, and what is the left side pointing at? Actually, only two of the three are needed, because any two determines the third. There are also functions for converting a rotation to this three vector representation, and vice versa. | ||
The rest of this article is presents the practical aspects of the LSL '''rotation''' type while avoiding delving into the complex inner workings of quaternion mathematics. | |||
*For a more technical article on '''rotations''' see {{LSLG|quaternion}}. | *For a more technical article on '''rotations''' see {{LSLG|quaternion}}. | ||
*For a compact list of functions and events related to rotations see {{LSLG|Rotation Synopsys}}. | *For a compact list of functions and events related to rotations see {{LSLG|Rotation Synopsys}}. | ||
Line 13: | Line 20: | ||
As a text note, when the LSL type '''rotation''' is referred to, it will be '''bold'''; when discussing rotations of a prim or real world object, not the LSL type itself, it will be written in roman. | As a text note, when the LSL type '''rotation''' is referred to, it will be '''bold'''; when discussing rotations of a prim or real world object, not the LSL type itself, it will be written in roman. | ||
In LSL all rotations are done according to the '''right hand rule'''. Make a fist with your right hand, | In LSL all rotations are done according to the '''right hand rule'''. Make a fist with your right hand, first finger extended in the direction of the positive direction of the x-axis. Your second finger will point at positive y-axis, and your thumb will point at positive z-axis . When you're editing an object, the three colored axis arrows point in the positive direction for each axis (X: red, Y: green, Z: blue). | ||
It is important to distinguish between the '''rotation''' reletive to the world, and the '''rotation'''reletive 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. | |||
To get the '''rotation''' of an unlinked prim, use: | To get the '''rotation''' in a script of an unlinked prim, use: | ||
<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 myRot ||= {{LSLG|llGetRot}}();||// load the | |rotation myRot ||= {{LSLG|llGetRot}}();||// load the world rotation into myRot | ||
|} | |} | ||
</div></div> | </div></div> | ||
Line 26: | Line 35: | ||
=== Combining Rotations === | === Combining Rotations === | ||
To combine '''rotations''', you use the '''multiply''' and '''divide''' operators | To combine '''rotations''', you use the '''multiply''' and '''divide''' operators. Don't try to use addition or subtraction operators on '''rotations''', as they will not do what you expect. | ||
Unlike other types such as {{LSLG|float}}, the order in which the operations are done is important. The reason for this is simple: the order you do rotations in is important in RL. For example, if you had a dart with four feathers, started from rotation <0, 0, 0> with its tail on the origin, it would lie on the X axis with its point aimed in the positive X direction, its feathers along the Z and Y axes, and the axes of the dart and the axes of the world would be aligned. We're going to rotate it 45 degrees around X and 30 degrees around Y, but in different orders. | Unlike other types such as {{LSLG|float}}, the order in which the operations are done is important. | ||
[http://en.wikipedia.org/wiki/Commutative non-commutative] | |||
The reason for this is simple: the order you do rotations in is important in RL. For example, if you had a dart with four feathers, started from rotation <0, 0, 0> with its tail on the origin, it would lie on the X axis with its point aimed in the positive X direction, its feathers along the Z and Y axes, and the axes of the dart and the axes of the world would be aligned. We're going to rotate it 45 degrees around X and 30 degrees around Y, but in different orders. | |||
First, after rotating 45 deg around X the dart would still be on the X axis, unmoved, just turned along its long axis, so the feathers would be at 45 deg to the axes. Then rotating 30 deg around Y would move it in the XZ plane to point down 30 deg from the X axis (remember the right hand rule for rotations means a small positive rotation around Y moves the point down). The dart winds up pointing 30 deg down, in the same vertical plane it started in, but turned around its own long axis so the feathers are no longer up and down. | First, after rotating 45 deg around X the dart would still be on the X axis, unmoved, just turned along its long axis, so the feathers would be at 45 deg to the axes. Then rotating 30 deg around Y would move it in the XZ plane to point down 30 deg from the X axis (remember the right hand rule for rotations means a small positive rotation around Y moves the point down). The dart winds up pointing 30 deg down, in the same vertical plane it started in, but turned around its own long axis so the feathers are no longer up and down. |
Revision as of 13:18, 19 February 2007
LSL Portal | Functions | Events | Types | Operators | Constants | Flow Control | Script Library | Categorized Library | Tutorials |
rotation
The LSL type used to hold a 3D angle is called a rotation. In LSL, a 3D angle is represented by a quaternion. You can think of a quaternion as three numbers that represent the direction an object is facing, and a fourth number that represents the object's orientation around that direction. The main advantage of using these quaternions is that they are not susceptible to gimbal lock.
Another way to represent a rotation is using three numbers, <X, Y, Z>, which represent the rotation around each axis. This is used in the Edit window. In LSL, these three numbers are called the Euler representation of a rotation. For good reasons, the four number version is better, though harder for a beginner to grasp. There are functions for converting easily back and forth.
A third way is to use three vectors. What is the front pointing at, what is the top pointing at, and what is the left side pointing at? Actually, only two of the three are needed, because any two determines the third. There are also functions for converting a rotation to this three vector representation, and vice versa.
The rest of this article is presents the practical aspects of the LSL rotation type while avoiding delving into the complex inner workings of quaternion mathematics.
- For a more technical article on rotations see quaternion.
- For a compact list of functions and events related to rotations see Rotation Synopsys.
- There is also information about rotating textures in textures.
As a text note, when the LSL type rotation is referred to, it will be bold; when discussing rotations of a prim or real world object, not the LSL type itself, it will be written in roman.
In LSL all rotations are done according to the right hand rule. Make a fist with your right hand, first finger extended in the direction of the positive direction of the x-axis. Your second finger will point at positive y-axis, and your thumb will point at positive z-axis . When you're editing an object, the three colored axis arrows point in the positive direction for each axis (X: red, Y: green, Z: blue).
It is important to distinguish between the rotation reletive to the world, and the rotationreletive 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.
To get the rotation in a script of an unlinked prim, use:
rotation myRot | = llGetRot(); | // load the world rotation into myRot |
Combining Rotations
To combine rotations, you use the multiply and divide operators. Don't try to use addition or subtraction operators on rotations, as they will not do what you expect.
Unlike other types such as float, the order in which the operations are done is important. non-commutative The reason for this is simple: the order you do rotations in is important in RL. For example, if you had a dart with four feathers, started from rotation <0, 0, 0> with its tail on the origin, it would lie on the X axis with its point aimed in the positive X direction, its feathers along the Z and Y axes, and the axes of the dart and the axes of the world would be aligned. We're going to rotate it 45 degrees around X and 30 degrees around Y, but in different orders.
First, after rotating 45 deg around X the dart would still be on the X axis, unmoved, just turned along its long axis, so the feathers would be at 45 deg to the axes. Then rotating 30 deg around Y would move it in the XZ plane to point down 30 deg from the X axis (remember the right hand rule for rotations means a small positive rotation around Y moves the point down). The dart winds up pointing 30 deg down, in the same vertical plane it started in, but turned around its own long axis so the feathers are no longer up and down.
If you did it the other way, first rotating 30 deg in Y, the dart would rotate down in the XZ plane, but notice that it no longer is on the X axis, its X axis and the world's aren't aligned any more. Now a 45 degree rotation around the X axis would pivot the dart around its tail, the point following a 30 deg cone whose axis is along the positive world X axis, for 45 degrees up and to the right. If you were looking down the X axis, it would pivot from pointing 30 deg below the X axis, up and to the right, out of the XZ plane, to a point below the 1st quadrant in the XY plane, its feathers rotating as it went.
Clearly this is a different result from the first rotation, but the order of rotation is the only thing changed.
To do a constant rotation you need to define a rotation value which can be done by creating a vector with the X, Y, Z angles in radians as components (called an Euler angle), then converting that to a rotation by using the llEuler2Rot function. This seems an unnecessary complication, but the actual values of the rotation fields are extremely non-intuitive, so practically, define your rotations as vector then convert them to rotations. To go from a rotation to and Euler angle vector use llRot2Euler.
NOTE: angles in LSL are in radians not degrees, but you can easily convert by using the built in constants RAD_TO_DEG and DEG_TO_RAD. For a 30 degree rotation around the X axis you might use:
rotation rot30X | = llEuler2Rot(<30, 0,0> * DEG_TO_RAD); | // convert the degrees to radians, then convert that vector into a rotation, rot30x |
vector vec30X | = llRot2Euler(rot30X ); | // convert the rotation back to a vector (the values will be in radians) |
Local vs Global rotations
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 rotation by putting the constant 30 degree rotation to the left of the object's rotation. It is like the first operation in the first example above, just twisting the dart 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.
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, a local rotation.
In the globalRot case, again starting from <0, 0, 0>, first the object is rotated to its original rotation, but the object's axes and the world's axes are no longer aligned! So, now 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). Normally this isn't of much interest since the values are non-intuitive, but 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.
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.