https://wiki.secondlife.com/w/api.php?action=feedcontributions&user=Jonno+Stromfield&feedformat=atomSecond Life Wiki - User contributions [en]2019-10-14T03:23:13ZUser contributionsMediaWiki 1.23.7https://wiki.secondlife.com/wiki/Talk:LlGetTimeTalk:LlGetTime2010-12-02T12:00:36Z<p>Jonno Stromfield: </p>
<hr />
<div>The last edit lost the point that llGetTime returns results more precise than whole seconds, such as results that differ by more than zero yet less than one. -- [[User:Ppaatt Lynagh|Ppaatt Lynagh]] 13:26, 24 October 2007 (PDT)</div>Jonno Stromfieldhttps://wiki.secondlife.com/wiki/Talk:LlGetTimeTalk:LlGetTime2010-12-02T11:55:29Z<p>Jonno Stromfield: </p>
<hr />
<div>The last edit lost the point that llGetTime returns results more precise than whole seconds, such as results that differ by more than zero yet less than one. -- [[User:Ppaatt Lynagh|Ppaatt Lynagh]] 13:26, 24 October 2007 (PDT)<br />
<br />
It needs to be mentioned that some sim resets will reset llGetTime. [[User:Jonno Stromfield|Jonno Stromfield]] 11:55, 2 December 2010 (UTC)</div>Jonno Stromfieldhttps://wiki.secondlife.com/wiki/User:Strife_Onizuka/PRIM_NAMEUser:Strife Onizuka/PRIM NAME2010-11-19T10:27:45Z<p>Jonno Stromfield: </p>
<hr />
<div>{{User:Strife_Onizuka/Constant<br />
|comment=Used to get or set the prim's name.<br />
|scope=prim<br />
|attr=name<br />
|name=PRIM_NAME<br />
|type=integer<br />
|value=27<br />
|desc=Used to get or set the prim's name.<br />
|r1_type=string|r1_name=name<br />
|text-get<br />
|text-set<br />
|examples=<br />
|constants=<br />
|functions=<br />
{{LSL DefineRow||[[llSetPrimitiveParams]]|}}<br />
{{LSL DefineRow||[[llSetLinkPrimitiveParams]]|}}<br />
{{LSL DefineRow||[[llSetLinkPrimitiveParamsFast]]|}}<br />
{{LSL DefineRow||[[llGetPrimitiveParams]]|}}<br />
{{LSL DefineRow||[[llGetLinkPrimitiveParams]]|}}<br />
{{LSL DefineRow||[[llGetObjectName]]|}}<br />
{{LSL DefineRow||[[llSetObjectName]]|}}<br />
{{LSL DefineRow||[[llGetObjectDetails]]|}}<br />
|events<br />
|location<br />
<!--|cat1=Prim<br />
|cat2=PrimitiveParams--><br />
|cat3<br />
|cat4<br />
|mode=user<br />
}}</div>Jonno Stromfieldhttps://wiki.secondlife.com/wiki/Talk:LlSetForceTalk:LlSetForce2010-11-13T16:15:54Z<p>Jonno Stromfield: </p>
<hr />
<div>llSetForce() seems to be at the least prim dependent. That is, two scripts in the same prim cannot set different values. One will cancel the other out. This was tested on an attachment. I did not test scripts in multiple prims in a single object, nor multiple attachments on an avatar. --[[User:Stickman Ingmann|Stickman]] 01:23, 18 September 2008 (PDT)<br />
:That is correct, furthermore none of the physics functions are script specific. -- '''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 07:21, 18 September 2008 (PDT)<br />
<br />
:If you set the force then remove the script, the force stops, but the size/direction still seems to be a prim property. If you set force = a in one script then force = b in a second script and delete the second script, force b continues to be applied. It needs the presence of a script giving a force but the vector value is the last set. [[User:Jonno Stromfield|Jonno Stromfield]] 16:15, 13 November 2010 (UTC)<br />
<br />
Can you turn this off just by setting it to ZERO_VECTOR? -- [[User:Sayrah Parx|Sayrah Parx]] 11:01, 5 January 2009 (UTC)</div>Jonno Stromfieldhttps://wiki.secondlife.com/wiki/Talk:LlSameGroupTalk:LlSameGroup2010-08-27T10:31:41Z<p>Jonno Stromfield: </p>
<hr />
<div>According to LSLWiki, "Passing NULL_KEY as id will return TRUE if the object's active group is set to "none", FALSE otherwise". If this is indeed a solid specification, it should be mentioned here. You often need to recognize this, particularly because of the "no group is same group" behavior, necessitating this extra check if you want to restrict some functionality to an actual group. -- [[User:Tali Rosca|Tali Rosca]] 14:40, 29 January 2009 (UTC)<br />
:Tested and added =) --[[Image:Zai_signature.png|45px]] '''[[User:Zai Lynch|Lynch]]''' <sup><small>([[User talk:Zai Lynch|talk]]|[[Special:Contributions/Zai Lynch|contribs]])</small></sup> 15:34, 29 January 2009 (UTC)<br />
<br />
A small test suggests that llSameGroup tests against the prim's group, not the object's. The main page explains that a child prim may be of a different group than the root. If the script is in the child, the test is against the child prim's group, not the root's. [[User:Jonno Stromfield|Jonno Stromfield]] 10:31, 27 August 2010 (UTC)</div>Jonno Stromfieldhttps://wiki.secondlife.com/wiki/LlParseStringKeepNullsLlParseStringKeepNulls2010-05-21T05:36:38Z<p>Jonno Stromfield: </p>
<hr />
<div>{{LSL_Function<br />
{{#vardefine:p_src_desc|source string}}<br />
{{#vardefine:p_separators_desc|separators to be discarded}}<br />
{{#vardefine:p_spacers_desc|spacers to be kept}}<br />
{{#vardefine:p_ParseStringKeepNulls_desc|boolean}}<br />
|func_id=285|func_sleep=0.0|func_energy=10.0<br />
|func=llParseStringKeepNulls|return_type=list|p1_type=string|p1_name=src|p2_type=list|p2_name=separators|p3_type=list|p3_name=spacers<br />
|func_footnote<br />
|func_desc<br />
|return_text=that is '''src''' broken into a list, discarding '''separators''', keeping '''spacers''', keeping any null values generated.<br />
|spec=<br />
The behavior is identical to that for [[llParseString2List]], except blank strings found in the list are kept. This is useful when parsing a list that contains values that can be null or empty (and subsequently removing the nulls would upset the distribution of data and the element indexes).<br />
<br />
llParseStringKeepNulls("", ["~"], []) will return [""]<br />
|caveats=<br />
* Only the first 8 separators and first 8 spacers will be used any extras will be ignored.<br />
* All separators and spacers must be strings, all other types will be ignored.<br />
* Separators take precedent over spacers. The string is parsed from start to finish, each position is compared against the separators then spacers before moving onto the next position.<br />
* Duplicates are ignored.<br />
* All entries in the return are typed as string. Use explicit typecasting on [[llList2String]] to convert the values into other types. Do not rely upon the implicit typecasting of the other llList2* functions (as they typically return a default value).<br />
* Remember to capture the result of the operation with a variable, unless you are planning to act directly on the results.<br />
|constants<br />
|examples=<lsl>default<br />
{<br />
state_entry()<br />
{<br />
// This will say:<br />
// <A><crazy><fox><.><Saw><the><moon><.><.><br />
string my_string = "A crazy fox. Saw the moon..";<br />
list my_list = llParseString2List(my_string,[" "],["."]);<br />
llOwnerSay("<" + llDumpList2String(my_list,"><") + ">");<br />
<br />
// This will say:<br />
// <A><crazy><fox><.><><><Saw><the><moon><.><><.><><br />
my_list = llParseStringKeepNulls(my_string,[" "],["."]);<br />
llOwnerSay("<" + llDumpList2String(my_list,"><") + ">");<br />
}<br />
}</lsl><br />
|helpers=<br />
'''Replacement functions without or very large separator/spacer count limits'''<br />
{{{!}}<br />
{{LSL DefineRow||[[ParseString2List]]|Functions exactly the same as [[llParseString2List]] and [[llParseStringKeepNulls]].}}<br />
{{LSL DefineRow||[[Separate Words|separateWords]]|Functions the same as [[llParseString2List]] unless certain preconditions are not met.}}<br />
{{!}}}<br />
|also_functions={{LSL DefineRow||[[llParseString2List]]}}<br />
{{LSL DefineRow||[[llDumpList2String]]}}<br />
{{LSL DefineRow||[[llCSV2List]]}}<br />
{{LSL DefineRow||[[llList2CSV]]}}<br />
|also_events<br />
|also_tests<br />
|also_articles<br />
|notes<br />
|sort=ParseStringKeepNulls<br />
|cat1=List<br />
|cat2=String<br />
|cat3=Data Conversion<br />
|cat4<br />
}}</div>Jonno Stromfieldhttps://wiki.secondlife.com/wiki/PrimitivePrimitive2010-04-26T11:27:57Z<p>Jonno Stromfield: /* Materials */</p>
<hr />
<div>{{Help<br />
|BugFixes=<br />
|Avatar=<br />
|Object=<br />
|LandSim=<br />
|Community=<br />
|Viewer=<br />
|Communication=<br />
|Multimedia=<br />
|Navigation=<br />
|Misc=<br />
|Description=<br />
|Wiki=<br />
|Glossary=*<br />
}}<br />
<br />
{{Otheruses4|primitives|[[LSL]] related information|:Category:LSL Prim}}<br />
<br />
A '''primitive''', or '''prim''', is a single-part [[object]]. Multi-part objects will have multiple parts ("prims").<br />
<br />
In [[Second Life]], virtual physical objects such as cars, houses, jewelry, and even less obvious things like [[hair]] and [[clothing]] are made out of one or more prims. Objects made from prims are usually created in-world using the built-in [[edit window|object editing tool]]. This tool is used for all sorts of 3D modeling in Second Life, playing the same role as 3D Max, Maya, or Blender, but customized for the Second Life way of doing things. <br />
<br />
Each prim is represented by a set of parameters, including shape/type, [[position]], [[scale]]/size, [[rotation]], [[cut]], [[hollow]], [[twist]], [[shear]], etc. These parameters are sent from a [[server]] to the [[viewer]] running on the [[resident]]'s desktop, where the local video card is used to render the visual appearance of everything. (Rendering on the server would probably create a much higher amount of network traffic.)<br />
<br />
The [[color]], [[texture]], [[bumpiness]], [[shininess]], and [[transparency]] of prims can also be adjusted, and images ([[textures]]) can be applied to each surface ([[face]]/side) of a prim to change its appearance. Box, cylinder, and prism prim shape types can also be made [[flexible]].<br />
<br />
Prims can be linked together into [[link set]]s. They can also be attached to avatars, but this process is separate from (thought similar to) linking. <br />
<br />
In the Viewer [[source code]], primitives are implemented in LLPrimitive, with vertex generation performed in LLVolume and rendering in LLVOVolume.<br />
<br />
==Shape types==<br />
There are eight primitive shape types:<br />
# box: all kinds of rectangular shapes<br />
# cylinder: round tables, floors, long pipes<br />
# prism: a box with one very small face<br />
# sphere: can be used for ellipsoids of all shapes<br />
# torus: most complex, can be modified in many exotic ways<br />
# tube: another form of hollow cylinder<br />
# ring: another variant of torus<br />
# [[sculpt]]ed: new as of 2007, used for highly variable organic shapes<br />
<br />
==Properties==<br />
<br />
{| {{Prettytable}}<br />
|+ '''Property survival'''<br />
|- {{Hl2}}<br />
! Property<br />
! Script Set Not Running<br />
! Script Removal<br />
! Take unscripted and re-rez<br />
! Shift-drag-copy<br />
|-<br />
|| [[llSitTarget|Sit Target]] || Yes || Yes || Yes || ?<br />
|-<br />
|| [[llParticleSystem|Particles]] || Yes || Yes || Yes || ?<br />
|-<br />
|| [[llSetText|Floating Text]] || Yes || Yes || Yes || No<br />
|-<br />
|| [[llTargetOmega|Spin]] || Yes || No || ? || ?<br />
|-<br />
|| [[llCollisionSound|Collision Sound]] || Yes || Yes || ? || ?<br />
|-<br />
|| [[llLoopSound|Looped Sound]] || Yes || Yes || Yes || No<br />
|-<br />
|| [[llSetRemoteScriptAccessPin|Remote Script Access Pin]] || Yes || Yes || ? || ?<br />
|-<br />
|| [[PRIM_POINT_LIGHT|Light]] || Yes || Yes || Yes || Yes<br />
|-<br />
|| {{LSLGC|Status}} || Yes || Yes || Yes || Yes<br />
|-<br />
|| [[llSetBuoyancy|Buoyancy]] <br />
|| ? || No || No || ?<br />
|-<br />
|| [[llSetTextureAnim|Texture Animation]]<br />
|| Yes || Yes || Yes || No<br />
|}<br />
<br />
It should be noted that when a script (in an object) moves from one simulator into another while being set as "Not Running" (either by [[llSetScriptState]] or via the checkbox in the script editor) the script's state will be lost. See {{Jira|SVC-1853}} for details.<br />
<br />
* {{Jira|SVC-3925}}<br />
* {{Jira|VWR-640}}<br />
* {{Jira|SVC-1242}}<br />
<br />
==Materials==<br />
There are seven primitive [[material]] types that determine things like friction and sound:<br />
# stone<br />
# metal<br />
# glass<br />
# wood<br />
# flesh<br />
# plastic <br />
# rubber<br />
<br />
==Help==<br />
* [[Basic Prim Creation and Editing]]<br />
<br />
==Scripting==<br />
* [[:Category:LSL_Prim]]<br />
<br />
==Video tutorials==<br />
* [[Video Tutorial/What is a prim?]]<br />
* [[Video Tutorial/Prim and mesh hair differences]]<br />
<br />
===See also===<br />
* [[Invisiprim]]<br />
* [[Mega Prim]]<br />
* [[Object]]<br />
* [[Prims]]<br />
* [[Prim and Object Hierarchy]]<br />
* [[Prim flicker]]<br />
* [[Primfficiency]]<br />
* [[Sculpted prim]]<br />
<br />
==External links==<br />
* [http://en.wikipedia.org/wiki/Geometric_primitive Wikipedia: Geometric primitive]</div>Jonno Stromfieldhttps://wiki.secondlife.com/wiki/RotationRotation2009-10-21T14:52:57Z<p>Jonno Stromfield: /* Axis plus Angle */</p>
<hr />
<div>{{LSL Header|ml=*}}{{RightToc}}<br />
==Rotation==<br />
The LSL '''rotation''' type is one of several ways to represent an orientation in 3D. (Note that we try to write the type name in '''bold'''.)<br />
<br />
The '''rotation''' can be viewed as a discrete twist in three dimensional space, and the orientation of an object is how much it has been twisted around from whichever axes we are using - normally the region's axes.<br />
<br />
It is a mathematical object called a {{LSLG|quaternion}}. You can think of a quaternion as four numbers, three of which represent the direction an object is facing and a fourth that represents the object's banking left or right around that direction. The main advantage of using <br />
quaternions is that they are not susceptible to [http://en.wikipedia.org/wiki/Gimbal_Lock gimbal lock]. <br />
For the complex inner workings of quaternion mathematics, see {{LSLG|quaternion}}. <br />
For a list of functions and events related to rotations see {{LSLG|LSL Rotation Synopsis}}.<br />
There is also information about causing textures to rotate in {{LSLG|texture}}s.<br />
<br />
==Other representations==<br />
===Euler vector===<br />
Another way to represent a 3D angle is using three numbers, <X, Y, Z>, which represent the amount which the object is rotated around each axis. This is used in the Edit window, for example, and is generally easy for people to visualize. It is easy to adjust the Rotation <x, y, z> numbers in the Edit window and see how the object behaves. Note that in the Edit window, the numbers are in degrees, that is, a right angle is 90.<br />
<br />
In LSL, these three angles are expressed in [[radians]] instead of degrees, that is, a right angle is PI/2. (A radian is sort of a very fat degree.)<br />
Note that these three numbers are a '''vector''' type and not a '''rotation''' type, though it can represent the same information. This is called the ''Euler'' representation of a 3D angle. In LSL the rotation around z is done first, then around y, and finally around x.<br />
<br />
===Axis plus Angle===<br />
In this method you define an axis of rotation, like defining the axis about which the earth spins, and use that together with the angle of rotation about the axis, which defines the amount of turn, to give the '''rotation'''.<br />
<br />
So if you want to define a '''rotation''' about an axis at 45 degrees in the x-y plane (North East in region coordinates), you'd need to point the axis with the same amount of x and y, but with no z. The axis could be <1.0, 1.0, 0.0>. The absolute size of the numbers defining the axis don’t matter in this representation; <2.0, 2.0, 0.0> would work just as well. The angle of rotation is a separate number given in radians, eg. PI/3 = 60 degrees. Together they define a global '''rotation''' of 60 degrees about the North East axis.<br />
<br />
Like a quaternion Axis plus Angle uses four numbers, but it doesn't need to be "normalized".<br />
<br />
===FWD, LEFT, UP=== <br />
Another way to represent the same 3D angle is to use three vectors, showing what the front is pointing at (fwd), what the top is pointing at (up), and what the left side is pointing at (left). Actually, only two of the three are needed, because any two determines the third. <br />
<br />
For good reasons, such as being able to easily combine rotations, the four number version, the quaternion '''rotation''', is better, though perhaps harder for a beginner to grasp. Fortunately it's very seldom necessary to do anything with the actual internal representation of ''rotations'' and there are functions for converting easily back and forth between the three LSL types, and between degrees and radians.<br />
<br />
==Right hand rule==<br />
In LSL all rotations are done according to the '''right hand rule'''. With your right hand, extend the first finger in the direction of the positive direction of the x-axis. Extend your second finger at right angles to your first finger, it will point along the positive y-axis, and your thumb, extended at right angles to both will point along the 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).<br />
<br />
http://en.wikipedia.org/wiki/Right_hand_rule<br />
<br />
Now, don't remove your right hand just yet, there is another use for it, determining the direction of a positive rotation. Make a fist with your right hand, thumb extended and pointing in the positive direction of the axis you are interested in. Your fingers curl around in the direction of positive rotation. Rotations around the X, Y, and Z axis are often referred to as Roll, Pitch, and Yaw, particularly for vehicles.<br />
<br />
[http://en.wikipedia.org/wiki/Tait-Bryan_angles Roll Pitch Yaw]<br />
<br />
== Combining Rotations ==<br />
'<br />
Suppose you have two rotations. ''r1'' is rotate 90 degrees to the left, and ''r2'' is rotate 30 degrees to the right. (Any rotations will work; these are just an example.)<br />
You can combine ''r1'' and ''r2'' to make ''r3'' using the '''*''' operator. It doesn't really multiply them, it ''composes'' them.<br />
<lsl><br />
rotation r3 = r1 * r2;<br />
</lsl><br />
The result in this case is that ''r3'' means rotate 60 degrees to the left.<br />
<br />
In other words, 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. The '''multiply''' operation applies the rotation in the positive direction, the '''divide''' operation does a negative rotation. You can also negate a rotation directly, just negate the s component, e.g. X.s = -X.s.<br />
<br />
Unlike other types such as {{LSLG|float}}, the order in which the operations are done, <br />
[http://en.wikipedia.org/wiki/Commutative non-commutative], is important.<br />
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.<br />
<br />
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.<br />
<br />
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.<br />
<br />
Clearly this is a different result from the first rotation, but the order of rotation is the only thing changed.<br />
<br />
To do a constant rotation you need to define a '''rotation''' value which can be done by creating a {{LSLG|vector}} with the X, Y, Z angles in radians as components (called an Euler angle), then converting that to a '''rotation''' by using the {{LSLG|llEuler2Rot}} function. To go from a rotation to an Euler angle {{LSLG|vector}} use {{LSLG|llRot2Euler}}.<br />
<br />
If you want an axial rotation you insert the axis of rotation and the turn angle into the {{LSLG|llAxisAngle2Rot}} function, and this will return the '''rotation'''. To go from a rotation back to axis and angle, use {{LSLG|llRot2Axis}} and {{LSLG|llRot2Angle}} respectively.<br />
<br />
You can alternately create the native rotation directly: the real part is the cosine of half the angle of rotation, and the vector part is the normalized axis of rotation multiplied by the sine of half the angle of rotation.<br />
<br />
'''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:<br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rot30X<br />
| style="white-space: nowrap" |= [[llEuler2Rot]](<30, 0, 0> * [[DEG_TO_RAD]]);<br />
||// convert the degrees to radians, then convert that [[vector]] into a rotation, rot30x<br />
|- valign="top"<br />
| style="white-space: nowrap" |[[vector]] vec30X <br />
| style="white-space: nowrap" |= [[llRot2Euler]](rot30X );<br />
||// convert the rotation back to a [[vector]] (the values will be in radians)<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rot30X<br />
| style="white-space: nowrap" |= [[llAxisAngle2Rot]](<1, 0, 0>, 30 * [[DEG_TO_RAD]]);<br />
||// convert the degrees to radians, then convert into a rotation, rot30x<br />
|}<br />
</div></div><br />
<br />
== Differences between math's quaternions and LSL rotations ==<br />
<br />
There are a few differences between LSL and maths that have little consequences while scripting, but that might puzzle people with prior mathematical knowledge. So we thought it would be good to list them here:<br />
<br />
* In LSL, all quaternions are normalized (the dot product of '''R''' by '''R''' is always '''1'''), and therefore represent ways to rotate objects without changing their size. In maths, generic quaternions might be not normalized, and they represent ''affinities'', i.e. a way to rotate '''and''' change the size of objects.<br />
* In LSL, the '''s''' term is the fourth member of the rotation: '''<x, y, z, s>'''. In maths, the '''s''' term, also called "real part", is written as the first coordinate of the quaternion: '''(s, x, y, z)'''.<br />
* Multiplication is written in reverse order in LSL and in maths. In LSL, you would write '''R * S''', where in maths you would write '''S . R'''.<br />
<br />
== Order of rotation for Euler Vectors ==<br />
<br />
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.<br />
<br />
== Local vs Global (World) rotations ==<br />
<br />
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.<br />
<br />
'''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.<br />
<br />
In LSL, the difference between doing a '''local''' or '''global''' rotation is the order the '''rotations''' are evaluated in the statement.<br />
<br />
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. <br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation localRot = <br />
| style="white-space: nowrap" |rot30X * myRot;<br />
||// do a local rotation by multiplying a constant rotation by a world rotation<br />
|}<br />
</div></div><br />
<br />
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.<br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation globalRot <br />
| style="white-space: nowrap" | = myRot * rot30X;<br />
||// do a global rotation by multiplying a world rotation by a constant rotation<br />
|}<br />
</div></div><br />
<br />
== Another way to think about combining rotations ==<br />
<br />
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.<br />
<br />
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.<br />
<br />
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.<br />
<br />
'''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'''.<br />
<br />
==Using Rotations ==<br />
<br />
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 [[float]]s, but there is overhead in unpacking them.<br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rot30X <br />
| style="white-space: nowrap" |= [[llEuler2Rot]](<30, 0, 0> * [[#DEG_TO_RAD|DEG_TO_RAD]] );<br />
||// Create a rotation constant<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rotCopy <br />
| style="white-space: nowrap" |= rot30X;<br />
||// Just copy it into rotCopy, it copies all 4 float components<br />
|- valign="top"<br />
| style="white-space: nowrap" |float X <br />
| style="white-space: nowrap" |= rotCopy.x;<br />
||// Get out the individual components of the rotation<br />
|- valign="top"<br />
| style="white-space: nowrap" |float Y <br />
| style="white-space: nowrap" |= rotCopy.y;<br />
||<br />
|- valign="top"<br />
| style="white-space: nowrap" |float Z <br />
| style="white-space: nowrap" |= rotCopy.z;<br />
||<br />
|- valign="top"<br />
| style="white-space: nowrap" |float S <br />
| style="white-space: nowrap" |= rotCopy.s;<br />
||<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation anotherCopy <br />
| style="white-space: nowrap" |= <X, Y, Z, S>;<br />
||// Make another rotation out of the components<br />
|}<br />
</div></div><br />
<br />
<br />
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.<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rot330X <br />
| style="white-space: nowrap" |= <-rot30X.x, -rot30X.y, -rot30X.z, rot30X.s>;<br />
||// invert a rotation - NOTE the s component isn't negated<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation another330X <br />
| style="white-space: nowrap" |= [[#ZERO_ROTATION|ZERO_ROTATION]] / rot30X;<br />
||// invert a rotation by division, same result as rot330X<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation yetanother330X <br />
| style="white-space: nowrap" |= <rot30X.x, rot30X.y, rot30X.z, -rot30X.s>;<br />
||// not literally the same but works the same.<br />
|}<br />
</div></div><br />
<br />
==Single or Root Prims vs Linked Prims vs Attachments ==<br />
<br />
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.<br />
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.<br />
<br />
{{LSLRotGetSet}}<br />
<br />
==Rotating Vectors ==<br />
<br />
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.<br />
<br />
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 [[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.<br />
=== Position of Object Rotated Around A Relative Point ===<br />
<lsl>rotation vRotArc = llEuler2Rot( <30.0, 0.0, 0.0> * DEG_TO_RAD );<br />
//-- creates a rotation constant, 30 degrees around the X axis<br />
<br />
vector vPosOffset = <0.0, 1.0, 0.0>;<br />
//-- creates an offset one meter in the positive Y direction<br />
<br />
vector vPosRotOffset = vPosOffset * vRotArc;<br />
//-- rotates the offset to get the motion caused by the rotation<br />
<br />
vector vPosOffsetDiff = vPosOffset - vPosRotOffset;<br />
//-- gets the local difference between the current offset and the rotated one<br />
<br />
vector vPosRotDiff = vPosOffsetDiff * llGetRot();<br />
//-- rotates the difference in the offsets to be relative to the global rotation.<br />
<br />
vector vPosNew = llGetPos() + vPosRotDiff;<br />
//-- finds the prims new position by adding the rotated offset difference<br />
<br />
rotation vRotNew = vRotArc * llGetRot();<br />
//-- finds rot to continue facing offset point</lsl><br />
:in application, the same action as:<br />
<lsl>llSetPrimitiveParams( [PRIM_POSITION, llGetPos() + (vPosOffset - vPosOffset * vRotArc) * llGetRot(),<br />
PRIM_ROTATION, vRotArc * llGetRot()] );</lsl><br />
* The above method results in the orbiting object always having the same side facing the center. An alternative that preserves the orbiters rotation is as follows<br />
<lsl>llSetPrimitiveParams( [PRIM_POSITION, llGetPos() + (vPosOffset - vPosOffset * vRotArc) * llGetRot()];<br />
vPosOffset = vPosOffset * vRotArc;</lsl><br />
'''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. Also to get a full orbit, you'll need to repeat the listed steps (in a [[timer]] perhaps).<br />
<br />
=== Position of Relative Point Around Rotated Object ===<br />
To get a point relative to the objects current facing (such as used in rezzors)<br />
<lsl>vector vPosOffset = <0.0, 0.0, 1.0>;<br />
//-- creates an offset one meter in the positive Z direction.<br />
<br />
vector vPosRotOffset = vPosOffset * llGetRot();<br />
//-- rotate the offset to be relative to objects rotation<br />
<br />
vector vPosOffsetIsAt = llGetPos() + vPosRotOffset;<br />
//-- get the region position of the rotated offset</lsl><br />
:in application, the same action as:<br />
<lsl>llRezAtRoot( "Object", llGetPos() + vPosOffset * llGetRot(), ZERO_VECTOR, llGetRot(), 0 );</lsl><br />
<br />
==Useful Snippets==<br />
<lsl>integer IsRotation(string s)<br />
{<br />
list split = llParseString2List(s, [" "], ["<", ">", ","]);<br />
if(llGetListLength(split) != 9)//we must check the list length, or the next test won't work properly.<br />
return 0;<br />
return !((string)((rotation)s) == (string)((rotation)((string)llListInsertList(split, ["-"], 7))));<br />
//it works by trying to flip the sign on the S element of the rotation,<br />
//if it works or breaks the rotation then the values won't match.<br />
//if the rotation was already broken then the sign flip will have no affect and the values will match<br />
//we cast back to string so we can catch negative zero which allows for support of <0,0,0,0><br />
}//Strife Onizuka</lsl><br />
<br />
<br />
// Calculate a point at distance d in the direction the avatar id is facing<br />
<lsl>vector point_in_front_of( key id, float d )<br />
{<br />
list pose = llGetObjectDetails( id, [ OBJECT_POS, OBJECT_ROT ] );<br />
return ( llList2Vector( pose, 0 ) + < d, 0.0, 0.0 > * llList2Rot( pose, 1 ) );<br />
}// Mephistopheles Thalheimer</lsl><br />
<br />
<br />
// Rez an object o at a distance d from the end of the z axis.<br />
// The object is rezzed oriented to the rezzer<br />
<br />
<lsl>rez_object_at_end( string o, float d )<br />
{<br />
vector s = llGetScale();<br />
<br />
if( llGetInventoryType( o ) == INVENTORY_OBJECT )<br />
{<br />
llRezObject( o, llGetPos() + llRot2Up( llGetRot() ) * ( s.z / 2.0 + d ) , ZERO_VECTOR, llGetRot(), 0 );<br />
}<br />
}// Mephistopheles Thalheimer</lsl><br />
<br />
// Useful functions converted to LSL from [http://www.isner.com/tutorials/quatSpells/quaternion_spells_12.htm this page]:<br />
<br />
// Scale a rotation:<br />
<lsl>rotation ScaleQuat(rotation source, float ratio)<br />
{<br />
return llAxisAngle2Rot(llRot2Axis(source), ratio * llRot2Angle(source));<br />
}</lsl><br />
<br />
// Constrain a rotation to a given plane, defined by its normal, this is very useful for vehicles that remain horizontal in turns:<br />
<lsl>rotation ConstrainQuat2Plane(rotation source, vector normal)<br />
{<br />
return llAxisAngle2Rot(normal, <source.x, source.y, source.z> * normal * llRot2Angle(source));<br />
} // Jesrad Seraph</lsl><br />
<br />
// Slerp (rotation combination) function from [[Slerp]]:<br />
<lsl>rotation BlendQuats(rotation a, rotation b, float ratio)<br />
{<br />
return llAxisAngle2Rot(llRot2Axis(b /= a), ratio * llRot2Angle(b)) * a;<br />
}</lsl><br />
<br />
== Constants ==<br />
=== [[ZERO_ROTATION]] ===<br />
ZERO_ROTATION = <0.0, 0.0, 0.0, 1.0>;<br/><br />
A rotation constant representing a Euler angle of <0.0, 0.0, 0.0>.<br />
<br />
=== [[DEG_TO_RAD]] ===<br />
DEG_TO_RAD = 0.01745329238f;<br/><br />
A float constant that when multiplied by an angle in degrees gives the angle in radians.<br />
<br />
=== [[RAD_TO_DEG]] ===<br />
RAD_TO_DEG = 57.29578f;<br/><br />
A float constant when multiplied by an angle in radians gives the angle in degrees.<br />
<br />
<br />
[[Category:LSL_Types|Rotation]][[Category:LSL_Math]][[Category:LSL_Math/3D]][[Category:LSL Rotation]]</div>Jonno Stromfieldhttps://wiki.secondlife.com/wiki/RotationRotation2009-10-21T14:52:12Z<p>Jonno Stromfield: /* Axis plus Angle */</p>
<hr />
<div>{{LSL Header|ml=*}}{{RightToc}}<br />
==Rotation==<br />
The LSL '''rotation''' type is one of several ways to represent an orientation in 3D. (Note that we try to write the type name in '''bold'''.)<br />
<br />
The '''rotation''' can be viewed as a discrete twist in three dimensional space, and the orientation of an object is how much it has been twisted around from whichever axes we are using - normally the region's axes.<br />
<br />
It is a mathematical object called a {{LSLG|quaternion}}. You can think of a quaternion as four numbers, three of which represent the direction an object is facing and a fourth that represents the object's banking left or right around that direction. The main advantage of using <br />
quaternions is that they are not susceptible to [http://en.wikipedia.org/wiki/Gimbal_Lock gimbal lock]. <br />
For the complex inner workings of quaternion mathematics, see {{LSLG|quaternion}}. <br />
For a list of functions and events related to rotations see {{LSLG|LSL Rotation Synopsis}}.<br />
There is also information about causing textures to rotate in {{LSLG|texture}}s.<br />
<br />
==Other representations==<br />
===Euler vector===<br />
Another way to represent a 3D angle is using three numbers, <X, Y, Z>, which represent the amount which the object is rotated around each axis. This is used in the Edit window, for example, and is generally easy for people to visualize. It is easy to adjust the Rotation <x, y, z> numbers in the Edit window and see how the object behaves. Note that in the Edit window, the numbers are in degrees, that is, a right angle is 90.<br />
<br />
In LSL, these three angles are expressed in [[radians]] instead of degrees, that is, a right angle is PI/2. (A radian is sort of a very fat degree.)<br />
Note that these three numbers are a '''vector''' type and not a '''rotation''' type, though it can represent the same information. This is called the ''Euler'' representation of a 3D angle. In LSL the rotation around z is done first, then around y, and finally around x.<br />
<br />
===Axis plus Angle===<br />
In this method you define an axis of rotation, like defining the axis about which the earth spins, and use that together with the angle of rotation about the axis, which defines the amount of turn, to define the '''rotation'''.<br />
<br />
So if you want to define a '''rotation''' about an axis at 45 degrees in the x-y plane (North East in region coordinates), you'd need to point the axis with the same amount of x and y, but with no z. The axis could be <1.0, 1.0, 0.0>. The absolute size of the numbers defining the axis don’t matter in this representation; <2.0, 2.0, 0.0> would work just as well. The angle of rotation is a separate number given in radians, eg. PI/3 = 60 degrees. Together they define a global '''rotation''' of 60 degrees about the North East axis.<br />
<br />
Like a quaternion Axis plus Angle uses four numbers, but it doesn't need to be "normalized".<br />
<br />
===FWD, LEFT, UP=== <br />
Another way to represent the same 3D angle is to use three vectors, showing what the front is pointing at (fwd), what the top is pointing at (up), and what the left side is pointing at (left). Actually, only two of the three are needed, because any two determines the third. <br />
<br />
For good reasons, such as being able to easily combine rotations, the four number version, the quaternion '''rotation''', is better, though perhaps harder for a beginner to grasp. Fortunately it's very seldom necessary to do anything with the actual internal representation of ''rotations'' and there are functions for converting easily back and forth between the three LSL types, and between degrees and radians.<br />
<br />
==Right hand rule==<br />
In LSL all rotations are done according to the '''right hand rule'''. With your right hand, extend the first finger in the direction of the positive direction of the x-axis. Extend your second finger at right angles to your first finger, it will point along the positive y-axis, and your thumb, extended at right angles to both will point along the 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).<br />
<br />
http://en.wikipedia.org/wiki/Right_hand_rule<br />
<br />
Now, don't remove your right hand just yet, there is another use for it, determining the direction of a positive rotation. Make a fist with your right hand, thumb extended and pointing in the positive direction of the axis you are interested in. Your fingers curl around in the direction of positive rotation. Rotations around the X, Y, and Z axis are often referred to as Roll, Pitch, and Yaw, particularly for vehicles.<br />
<br />
[http://en.wikipedia.org/wiki/Tait-Bryan_angles Roll Pitch Yaw]<br />
<br />
== Combining Rotations ==<br />
'<br />
Suppose you have two rotations. ''r1'' is rotate 90 degrees to the left, and ''r2'' is rotate 30 degrees to the right. (Any rotations will work; these are just an example.)<br />
You can combine ''r1'' and ''r2'' to make ''r3'' using the '''*''' operator. It doesn't really multiply them, it ''composes'' them.<br />
<lsl><br />
rotation r3 = r1 * r2;<br />
</lsl><br />
The result in this case is that ''r3'' means rotate 60 degrees to the left.<br />
<br />
In other words, 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. The '''multiply''' operation applies the rotation in the positive direction, the '''divide''' operation does a negative rotation. You can also negate a rotation directly, just negate the s component, e.g. X.s = -X.s.<br />
<br />
Unlike other types such as {{LSLG|float}}, the order in which the operations are done, <br />
[http://en.wikipedia.org/wiki/Commutative non-commutative], is important.<br />
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.<br />
<br />
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.<br />
<br />
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.<br />
<br />
Clearly this is a different result from the first rotation, but the order of rotation is the only thing changed.<br />
<br />
To do a constant rotation you need to define a '''rotation''' value which can be done by creating a {{LSLG|vector}} with the X, Y, Z angles in radians as components (called an Euler angle), then converting that to a '''rotation''' by using the {{LSLG|llEuler2Rot}} function. To go from a rotation to an Euler angle {{LSLG|vector}} use {{LSLG|llRot2Euler}}.<br />
<br />
If you want an axial rotation you insert the axis of rotation and the turn angle into the {{LSLG|llAxisAngle2Rot}} function, and this will return the '''rotation'''. To go from a rotation back to axis and angle, use {{LSLG|llRot2Axis}} and {{LSLG|llRot2Angle}} respectively.<br />
<br />
You can alternately create the native rotation directly: the real part is the cosine of half the angle of rotation, and the vector part is the normalized axis of rotation multiplied by the sine of half the angle of rotation.<br />
<br />
'''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:<br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rot30X<br />
| style="white-space: nowrap" |= [[llEuler2Rot]](<30, 0, 0> * [[DEG_TO_RAD]]);<br />
||// convert the degrees to radians, then convert that [[vector]] into a rotation, rot30x<br />
|- valign="top"<br />
| style="white-space: nowrap" |[[vector]] vec30X <br />
| style="white-space: nowrap" |= [[llRot2Euler]](rot30X );<br />
||// convert the rotation back to a [[vector]] (the values will be in radians)<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rot30X<br />
| style="white-space: nowrap" |= [[llAxisAngle2Rot]](<1, 0, 0>, 30 * [[DEG_TO_RAD]]);<br />
||// convert the degrees to radians, then convert into a rotation, rot30x<br />
|}<br />
</div></div><br />
<br />
== Differences between math's quaternions and LSL rotations ==<br />
<br />
There are a few differences between LSL and maths that have little consequences while scripting, but that might puzzle people with prior mathematical knowledge. So we thought it would be good to list them here:<br />
<br />
* In LSL, all quaternions are normalized (the dot product of '''R''' by '''R''' is always '''1'''), and therefore represent ways to rotate objects without changing their size. In maths, generic quaternions might be not normalized, and they represent ''affinities'', i.e. a way to rotate '''and''' change the size of objects.<br />
* In LSL, the '''s''' term is the fourth member of the rotation: '''<x, y, z, s>'''. In maths, the '''s''' term, also called "real part", is written as the first coordinate of the quaternion: '''(s, x, y, z)'''.<br />
* Multiplication is written in reverse order in LSL and in maths. In LSL, you would write '''R * S''', where in maths you would write '''S . R'''.<br />
<br />
== Order of rotation for Euler Vectors ==<br />
<br />
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.<br />
<br />
== Local vs Global (World) rotations ==<br />
<br />
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.<br />
<br />
'''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.<br />
<br />
In LSL, the difference between doing a '''local''' or '''global''' rotation is the order the '''rotations''' are evaluated in the statement.<br />
<br />
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. <br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation localRot = <br />
| style="white-space: nowrap" |rot30X * myRot;<br />
||// do a local rotation by multiplying a constant rotation by a world rotation<br />
|}<br />
</div></div><br />
<br />
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.<br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation globalRot <br />
| style="white-space: nowrap" | = myRot * rot30X;<br />
||// do a global rotation by multiplying a world rotation by a constant rotation<br />
|}<br />
</div></div><br />
<br />
== Another way to think about combining rotations ==<br />
<br />
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.<br />
<br />
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.<br />
<br />
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.<br />
<br />
'''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'''.<br />
<br />
==Using Rotations ==<br />
<br />
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 [[float]]s, but there is overhead in unpacking them.<br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rot30X <br />
| style="white-space: nowrap" |= [[llEuler2Rot]](<30, 0, 0> * [[#DEG_TO_RAD|DEG_TO_RAD]] );<br />
||// Create a rotation constant<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rotCopy <br />
| style="white-space: nowrap" |= rot30X;<br />
||// Just copy it into rotCopy, it copies all 4 float components<br />
|- valign="top"<br />
| style="white-space: nowrap" |float X <br />
| style="white-space: nowrap" |= rotCopy.x;<br />
||// Get out the individual components of the rotation<br />
|- valign="top"<br />
| style="white-space: nowrap" |float Y <br />
| style="white-space: nowrap" |= rotCopy.y;<br />
||<br />
|- valign="top"<br />
| style="white-space: nowrap" |float Z <br />
| style="white-space: nowrap" |= rotCopy.z;<br />
||<br />
|- valign="top"<br />
| style="white-space: nowrap" |float S <br />
| style="white-space: nowrap" |= rotCopy.s;<br />
||<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation anotherCopy <br />
| style="white-space: nowrap" |= <X, Y, Z, S>;<br />
||// Make another rotation out of the components<br />
|}<br />
</div></div><br />
<br />
<br />
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.<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rot330X <br />
| style="white-space: nowrap" |= <-rot30X.x, -rot30X.y, -rot30X.z, rot30X.s>;<br />
||// invert a rotation - NOTE the s component isn't negated<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation another330X <br />
| style="white-space: nowrap" |= [[#ZERO_ROTATION|ZERO_ROTATION]] / rot30X;<br />
||// invert a rotation by division, same result as rot330X<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation yetanother330X <br />
| style="white-space: nowrap" |= <rot30X.x, rot30X.y, rot30X.z, -rot30X.s>;<br />
||// not literally the same but works the same.<br />
|}<br />
</div></div><br />
<br />
==Single or Root Prims vs Linked Prims vs Attachments ==<br />
<br />
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.<br />
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.<br />
<br />
{{LSLRotGetSet}}<br />
<br />
==Rotating Vectors ==<br />
<br />
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.<br />
<br />
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 [[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.<br />
=== Position of Object Rotated Around A Relative Point ===<br />
<lsl>rotation vRotArc = llEuler2Rot( <30.0, 0.0, 0.0> * DEG_TO_RAD );<br />
//-- creates a rotation constant, 30 degrees around the X axis<br />
<br />
vector vPosOffset = <0.0, 1.0, 0.0>;<br />
//-- creates an offset one meter in the positive Y direction<br />
<br />
vector vPosRotOffset = vPosOffset * vRotArc;<br />
//-- rotates the offset to get the motion caused by the rotation<br />
<br />
vector vPosOffsetDiff = vPosOffset - vPosRotOffset;<br />
//-- gets the local difference between the current offset and the rotated one<br />
<br />
vector vPosRotDiff = vPosOffsetDiff * llGetRot();<br />
//-- rotates the difference in the offsets to be relative to the global rotation.<br />
<br />
vector vPosNew = llGetPos() + vPosRotDiff;<br />
//-- finds the prims new position by adding the rotated offset difference<br />
<br />
rotation vRotNew = vRotArc * llGetRot();<br />
//-- finds rot to continue facing offset point</lsl><br />
:in application, the same action as:<br />
<lsl>llSetPrimitiveParams( [PRIM_POSITION, llGetPos() + (vPosOffset - vPosOffset * vRotArc) * llGetRot(),<br />
PRIM_ROTATION, vRotArc * llGetRot()] );</lsl><br />
* The above method results in the orbiting object always having the same side facing the center. An alternative that preserves the orbiters rotation is as follows<br />
<lsl>llSetPrimitiveParams( [PRIM_POSITION, llGetPos() + (vPosOffset - vPosOffset * vRotArc) * llGetRot()];<br />
vPosOffset = vPosOffset * vRotArc;</lsl><br />
'''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. Also to get a full orbit, you'll need to repeat the listed steps (in a [[timer]] perhaps).<br />
<br />
=== Position of Relative Point Around Rotated Object ===<br />
To get a point relative to the objects current facing (such as used in rezzors)<br />
<lsl>vector vPosOffset = <0.0, 0.0, 1.0>;<br />
//-- creates an offset one meter in the positive Z direction.<br />
<br />
vector vPosRotOffset = vPosOffset * llGetRot();<br />
//-- rotate the offset to be relative to objects rotation<br />
<br />
vector vPosOffsetIsAt = llGetPos() + vPosRotOffset;<br />
//-- get the region position of the rotated offset</lsl><br />
:in application, the same action as:<br />
<lsl>llRezAtRoot( "Object", llGetPos() + vPosOffset * llGetRot(), ZERO_VECTOR, llGetRot(), 0 );</lsl><br />
<br />
==Useful Snippets==<br />
<lsl>integer IsRotation(string s)<br />
{<br />
list split = llParseString2List(s, [" "], ["<", ">", ","]);<br />
if(llGetListLength(split) != 9)//we must check the list length, or the next test won't work properly.<br />
return 0;<br />
return !((string)((rotation)s) == (string)((rotation)((string)llListInsertList(split, ["-"], 7))));<br />
//it works by trying to flip the sign on the S element of the rotation,<br />
//if it works or breaks the rotation then the values won't match.<br />
//if the rotation was already broken then the sign flip will have no affect and the values will match<br />
//we cast back to string so we can catch negative zero which allows for support of <0,0,0,0><br />
}//Strife Onizuka</lsl><br />
<br />
<br />
// Calculate a point at distance d in the direction the avatar id is facing<br />
<lsl>vector point_in_front_of( key id, float d )<br />
{<br />
list pose = llGetObjectDetails( id, [ OBJECT_POS, OBJECT_ROT ] );<br />
return ( llList2Vector( pose, 0 ) + < d, 0.0, 0.0 > * llList2Rot( pose, 1 ) );<br />
}// Mephistopheles Thalheimer</lsl><br />
<br />
<br />
// Rez an object o at a distance d from the end of the z axis.<br />
// The object is rezzed oriented to the rezzer<br />
<br />
<lsl>rez_object_at_end( string o, float d )<br />
{<br />
vector s = llGetScale();<br />
<br />
if( llGetInventoryType( o ) == INVENTORY_OBJECT )<br />
{<br />
llRezObject( o, llGetPos() + llRot2Up( llGetRot() ) * ( s.z / 2.0 + d ) , ZERO_VECTOR, llGetRot(), 0 );<br />
}<br />
}// Mephistopheles Thalheimer</lsl><br />
<br />
// Useful functions converted to LSL from [http://www.isner.com/tutorials/quatSpells/quaternion_spells_12.htm this page]:<br />
<br />
// Scale a rotation:<br />
<lsl>rotation ScaleQuat(rotation source, float ratio)<br />
{<br />
return llAxisAngle2Rot(llRot2Axis(source), ratio * llRot2Angle(source));<br />
}</lsl><br />
<br />
// Constrain a rotation to a given plane, defined by its normal, this is very useful for vehicles that remain horizontal in turns:<br />
<lsl>rotation ConstrainQuat2Plane(rotation source, vector normal)<br />
{<br />
return llAxisAngle2Rot(normal, <source.x, source.y, source.z> * normal * llRot2Angle(source));<br />
} // Jesrad Seraph</lsl><br />
<br />
// Slerp (rotation combination) function from [[Slerp]]:<br />
<lsl>rotation BlendQuats(rotation a, rotation b, float ratio)<br />
{<br />
return llAxisAngle2Rot(llRot2Axis(b /= a), ratio * llRot2Angle(b)) * a;<br />
}</lsl><br />
<br />
== Constants ==<br />
=== [[ZERO_ROTATION]] ===<br />
ZERO_ROTATION = <0.0, 0.0, 0.0, 1.0>;<br/><br />
A rotation constant representing a Euler angle of <0.0, 0.0, 0.0>.<br />
<br />
=== [[DEG_TO_RAD]] ===<br />
DEG_TO_RAD = 0.01745329238f;<br/><br />
A float constant that when multiplied by an angle in degrees gives the angle in radians.<br />
<br />
=== [[RAD_TO_DEG]] ===<br />
RAD_TO_DEG = 57.29578f;<br/><br />
A float constant when multiplied by an angle in radians gives the angle in degrees.<br />
<br />
<br />
[[Category:LSL_Types|Rotation]][[Category:LSL_Math]][[Category:LSL_Math/3D]][[Category:LSL Rotation]]</div>Jonno Stromfieldhttps://wiki.secondlife.com/wiki/RotationRotation2009-10-21T14:51:21Z<p>Jonno Stromfield: /* Axis plus Angle */</p>
<hr />
<div>{{LSL Header|ml=*}}{{RightToc}}<br />
==Rotation==<br />
The LSL '''rotation''' type is one of several ways to represent an orientation in 3D. (Note that we try to write the type name in '''bold'''.)<br />
<br />
The '''rotation''' can be viewed as a discrete twist in three dimensional space, and the orientation of an object is how much it has been twisted around from whichever axes we are using - normally the region's axes.<br />
<br />
It is a mathematical object called a {{LSLG|quaternion}}. You can think of a quaternion as four numbers, three of which represent the direction an object is facing and a fourth that represents the object's banking left or right around that direction. The main advantage of using <br />
quaternions is that they are not susceptible to [http://en.wikipedia.org/wiki/Gimbal_Lock gimbal lock]. <br />
For the complex inner workings of quaternion mathematics, see {{LSLG|quaternion}}. <br />
For a list of functions and events related to rotations see {{LSLG|LSL Rotation Synopsis}}.<br />
There is also information about causing textures to rotate in {{LSLG|texture}}s.<br />
<br />
==Other representations==<br />
===Euler vector===<br />
Another way to represent a 3D angle is using three numbers, <X, Y, Z>, which represent the amount which the object is rotated around each axis. This is used in the Edit window, for example, and is generally easy for people to visualize. It is easy to adjust the Rotation <x, y, z> numbers in the Edit window and see how the object behaves. Note that in the Edit window, the numbers are in degrees, that is, a right angle is 90.<br />
<br />
In LSL, these three angles are expressed in [[radians]] instead of degrees, that is, a right angle is PI/2. (A radian is sort of a very fat degree.)<br />
Note that these three numbers are a '''vector''' type and not a '''rotation''' type, though it can represent the same information. This is called the ''Euler'' representation of a 3D angle. In LSL the rotation around z is done first, then around y, and finally around x.<br />
<br />
===Axis plus Angle===<br />
In this method you define an axis of rotation, like defining the axis about which the earth spins, and use that together with the angle of rotation about the axis, which defines the amount of turn, to define the '''rotation'''.<br />
<br />
So if you want to define a '''rotation''' about an axis at 45 degrees in the x-y plane (North East in region coordinates), you'd need to point the axis with the same amount of x and y, but with no z. The axis could be <1.0, 1.0, 0.0>. The absolute size of the numbers defining the axis don’t matter in this representation; <2.0, 2.0, 0.0> would work just as well. The angle of rotation is a separate number given in radians, eg. PI/3 = 60 degrees. Together it defines a global '''rotation''' of 60 degrees about the North East axis.<br />
<br />
Like a quaternion this uses four numbers, but it doesn't need to be "normalized".<br />
<br />
===FWD, LEFT, UP=== <br />
Another way to represent the same 3D angle is to use three vectors, showing what the front is pointing at (fwd), what the top is pointing at (up), and what the left side is pointing at (left). Actually, only two of the three are needed, because any two determines the third. <br />
<br />
For good reasons, such as being able to easily combine rotations, the four number version, the quaternion '''rotation''', is better, though perhaps harder for a beginner to grasp. Fortunately it's very seldom necessary to do anything with the actual internal representation of ''rotations'' and there are functions for converting easily back and forth between the three LSL types, and between degrees and radians.<br />
<br />
==Right hand rule==<br />
In LSL all rotations are done according to the '''right hand rule'''. With your right hand, extend the first finger in the direction of the positive direction of the x-axis. Extend your second finger at right angles to your first finger, it will point along the positive y-axis, and your thumb, extended at right angles to both will point along the 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).<br />
<br />
http://en.wikipedia.org/wiki/Right_hand_rule<br />
<br />
Now, don't remove your right hand just yet, there is another use for it, determining the direction of a positive rotation. Make a fist with your right hand, thumb extended and pointing in the positive direction of the axis you are interested in. Your fingers curl around in the direction of positive rotation. Rotations around the X, Y, and Z axis are often referred to as Roll, Pitch, and Yaw, particularly for vehicles.<br />
<br />
[http://en.wikipedia.org/wiki/Tait-Bryan_angles Roll Pitch Yaw]<br />
<br />
== Combining Rotations ==<br />
'<br />
Suppose you have two rotations. ''r1'' is rotate 90 degrees to the left, and ''r2'' is rotate 30 degrees to the right. (Any rotations will work; these are just an example.)<br />
You can combine ''r1'' and ''r2'' to make ''r3'' using the '''*''' operator. It doesn't really multiply them, it ''composes'' them.<br />
<lsl><br />
rotation r3 = r1 * r2;<br />
</lsl><br />
The result in this case is that ''r3'' means rotate 60 degrees to the left.<br />
<br />
In other words, 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. The '''multiply''' operation applies the rotation in the positive direction, the '''divide''' operation does a negative rotation. You can also negate a rotation directly, just negate the s component, e.g. X.s = -X.s.<br />
<br />
Unlike other types such as {{LSLG|float}}, the order in which the operations are done, <br />
[http://en.wikipedia.org/wiki/Commutative non-commutative], is important.<br />
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.<br />
<br />
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.<br />
<br />
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.<br />
<br />
Clearly this is a different result from the first rotation, but the order of rotation is the only thing changed.<br />
<br />
To do a constant rotation you need to define a '''rotation''' value which can be done by creating a {{LSLG|vector}} with the X, Y, Z angles in radians as components (called an Euler angle), then converting that to a '''rotation''' by using the {{LSLG|llEuler2Rot}} function. To go from a rotation to an Euler angle {{LSLG|vector}} use {{LSLG|llRot2Euler}}.<br />
<br />
If you want an axial rotation you insert the axis of rotation and the turn angle into the {{LSLG|llAxisAngle2Rot}} function, and this will return the '''rotation'''. To go from a rotation back to axis and angle, use {{LSLG|llRot2Axis}} and {{LSLG|llRot2Angle}} respectively.<br />
<br />
You can alternately create the native rotation directly: the real part is the cosine of half the angle of rotation, and the vector part is the normalized axis of rotation multiplied by the sine of half the angle of rotation.<br />
<br />
'''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:<br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rot30X<br />
| style="white-space: nowrap" |= [[llEuler2Rot]](<30, 0, 0> * [[DEG_TO_RAD]]);<br />
||// convert the degrees to radians, then convert that [[vector]] into a rotation, rot30x<br />
|- valign="top"<br />
| style="white-space: nowrap" |[[vector]] vec30X <br />
| style="white-space: nowrap" |= [[llRot2Euler]](rot30X );<br />
||// convert the rotation back to a [[vector]] (the values will be in radians)<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rot30X<br />
| style="white-space: nowrap" |= [[llAxisAngle2Rot]](<1, 0, 0>, 30 * [[DEG_TO_RAD]]);<br />
||// convert the degrees to radians, then convert into a rotation, rot30x<br />
|}<br />
</div></div><br />
<br />
== Differences between math's quaternions and LSL rotations ==<br />
<br />
There are a few differences between LSL and maths that have little consequences while scripting, but that might puzzle people with prior mathematical knowledge. So we thought it would be good to list them here:<br />
<br />
* In LSL, all quaternions are normalized (the dot product of '''R''' by '''R''' is always '''1'''), and therefore represent ways to rotate objects without changing their size. In maths, generic quaternions might be not normalized, and they represent ''affinities'', i.e. a way to rotate '''and''' change the size of objects.<br />
* In LSL, the '''s''' term is the fourth member of the rotation: '''<x, y, z, s>'''. In maths, the '''s''' term, also called "real part", is written as the first coordinate of the quaternion: '''(s, x, y, z)'''.<br />
* Multiplication is written in reverse order in LSL and in maths. In LSL, you would write '''R * S''', where in maths you would write '''S . R'''.<br />
<br />
== Order of rotation for Euler Vectors ==<br />
<br />
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.<br />
<br />
== Local vs Global (World) rotations ==<br />
<br />
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.<br />
<br />
'''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.<br />
<br />
In LSL, the difference between doing a '''local''' or '''global''' rotation is the order the '''rotations''' are evaluated in the statement.<br />
<br />
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. <br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation localRot = <br />
| style="white-space: nowrap" |rot30X * myRot;<br />
||// do a local rotation by multiplying a constant rotation by a world rotation<br />
|}<br />
</div></div><br />
<br />
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.<br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation globalRot <br />
| style="white-space: nowrap" | = myRot * rot30X;<br />
||// do a global rotation by multiplying a world rotation by a constant rotation<br />
|}<br />
</div></div><br />
<br />
== Another way to think about combining rotations ==<br />
<br />
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.<br />
<br />
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.<br />
<br />
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.<br />
<br />
'''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'''.<br />
<br />
==Using Rotations ==<br />
<br />
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 [[float]]s, but there is overhead in unpacking them.<br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rot30X <br />
| style="white-space: nowrap" |= [[llEuler2Rot]](<30, 0, 0> * [[#DEG_TO_RAD|DEG_TO_RAD]] );<br />
||// Create a rotation constant<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rotCopy <br />
| style="white-space: nowrap" |= rot30X;<br />
||// Just copy it into rotCopy, it copies all 4 float components<br />
|- valign="top"<br />
| style="white-space: nowrap" |float X <br />
| style="white-space: nowrap" |= rotCopy.x;<br />
||// Get out the individual components of the rotation<br />
|- valign="top"<br />
| style="white-space: nowrap" |float Y <br />
| style="white-space: nowrap" |= rotCopy.y;<br />
||<br />
|- valign="top"<br />
| style="white-space: nowrap" |float Z <br />
| style="white-space: nowrap" |= rotCopy.z;<br />
||<br />
|- valign="top"<br />
| style="white-space: nowrap" |float S <br />
| style="white-space: nowrap" |= rotCopy.s;<br />
||<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation anotherCopy <br />
| style="white-space: nowrap" |= <X, Y, Z, S>;<br />
||// Make another rotation out of the components<br />
|}<br />
</div></div><br />
<br />
<br />
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.<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rot330X <br />
| style="white-space: nowrap" |= <-rot30X.x, -rot30X.y, -rot30X.z, rot30X.s>;<br />
||// invert a rotation - NOTE the s component isn't negated<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation another330X <br />
| style="white-space: nowrap" |= [[#ZERO_ROTATION|ZERO_ROTATION]] / rot30X;<br />
||// invert a rotation by division, same result as rot330X<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation yetanother330X <br />
| style="white-space: nowrap" |= <rot30X.x, rot30X.y, rot30X.z, -rot30X.s>;<br />
||// not literally the same but works the same.<br />
|}<br />
</div></div><br />
<br />
==Single or Root Prims vs Linked Prims vs Attachments ==<br />
<br />
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.<br />
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.<br />
<br />
{{LSLRotGetSet}}<br />
<br />
==Rotating Vectors ==<br />
<br />
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.<br />
<br />
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 [[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.<br />
=== Position of Object Rotated Around A Relative Point ===<br />
<lsl>rotation vRotArc = llEuler2Rot( <30.0, 0.0, 0.0> * DEG_TO_RAD );<br />
//-- creates a rotation constant, 30 degrees around the X axis<br />
<br />
vector vPosOffset = <0.0, 1.0, 0.0>;<br />
//-- creates an offset one meter in the positive Y direction<br />
<br />
vector vPosRotOffset = vPosOffset * vRotArc;<br />
//-- rotates the offset to get the motion caused by the rotation<br />
<br />
vector vPosOffsetDiff = vPosOffset - vPosRotOffset;<br />
//-- gets the local difference between the current offset and the rotated one<br />
<br />
vector vPosRotDiff = vPosOffsetDiff * llGetRot();<br />
//-- rotates the difference in the offsets to be relative to the global rotation.<br />
<br />
vector vPosNew = llGetPos() + vPosRotDiff;<br />
//-- finds the prims new position by adding the rotated offset difference<br />
<br />
rotation vRotNew = vRotArc * llGetRot();<br />
//-- finds rot to continue facing offset point</lsl><br />
:in application, the same action as:<br />
<lsl>llSetPrimitiveParams( [PRIM_POSITION, llGetPos() + (vPosOffset - vPosOffset * vRotArc) * llGetRot(),<br />
PRIM_ROTATION, vRotArc * llGetRot()] );</lsl><br />
* The above method results in the orbiting object always having the same side facing the center. An alternative that preserves the orbiters rotation is as follows<br />
<lsl>llSetPrimitiveParams( [PRIM_POSITION, llGetPos() + (vPosOffset - vPosOffset * vRotArc) * llGetRot()];<br />
vPosOffset = vPosOffset * vRotArc;</lsl><br />
'''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. Also to get a full orbit, you'll need to repeat the listed steps (in a [[timer]] perhaps).<br />
<br />
=== Position of Relative Point Around Rotated Object ===<br />
To get a point relative to the objects current facing (such as used in rezzors)<br />
<lsl>vector vPosOffset = <0.0, 0.0, 1.0>;<br />
//-- creates an offset one meter in the positive Z direction.<br />
<br />
vector vPosRotOffset = vPosOffset * llGetRot();<br />
//-- rotate the offset to be relative to objects rotation<br />
<br />
vector vPosOffsetIsAt = llGetPos() + vPosRotOffset;<br />
//-- get the region position of the rotated offset</lsl><br />
:in application, the same action as:<br />
<lsl>llRezAtRoot( "Object", llGetPos() + vPosOffset * llGetRot(), ZERO_VECTOR, llGetRot(), 0 );</lsl><br />
<br />
==Useful Snippets==<br />
<lsl>integer IsRotation(string s)<br />
{<br />
list split = llParseString2List(s, [" "], ["<", ">", ","]);<br />
if(llGetListLength(split) != 9)//we must check the list length, or the next test won't work properly.<br />
return 0;<br />
return !((string)((rotation)s) == (string)((rotation)((string)llListInsertList(split, ["-"], 7))));<br />
//it works by trying to flip the sign on the S element of the rotation,<br />
//if it works or breaks the rotation then the values won't match.<br />
//if the rotation was already broken then the sign flip will have no affect and the values will match<br />
//we cast back to string so we can catch negative zero which allows for support of <0,0,0,0><br />
}//Strife Onizuka</lsl><br />
<br />
<br />
// Calculate a point at distance d in the direction the avatar id is facing<br />
<lsl>vector point_in_front_of( key id, float d )<br />
{<br />
list pose = llGetObjectDetails( id, [ OBJECT_POS, OBJECT_ROT ] );<br />
return ( llList2Vector( pose, 0 ) + < d, 0.0, 0.0 > * llList2Rot( pose, 1 ) );<br />
}// Mephistopheles Thalheimer</lsl><br />
<br />
<br />
// Rez an object o at a distance d from the end of the z axis.<br />
// The object is rezzed oriented to the rezzer<br />
<br />
<lsl>rez_object_at_end( string o, float d )<br />
{<br />
vector s = llGetScale();<br />
<br />
if( llGetInventoryType( o ) == INVENTORY_OBJECT )<br />
{<br />
llRezObject( o, llGetPos() + llRot2Up( llGetRot() ) * ( s.z / 2.0 + d ) , ZERO_VECTOR, llGetRot(), 0 );<br />
}<br />
}// Mephistopheles Thalheimer</lsl><br />
<br />
// Useful functions converted to LSL from [http://www.isner.com/tutorials/quatSpells/quaternion_spells_12.htm this page]:<br />
<br />
// Scale a rotation:<br />
<lsl>rotation ScaleQuat(rotation source, float ratio)<br />
{<br />
return llAxisAngle2Rot(llRot2Axis(source), ratio * llRot2Angle(source));<br />
}</lsl><br />
<br />
// Constrain a rotation to a given plane, defined by its normal, this is very useful for vehicles that remain horizontal in turns:<br />
<lsl>rotation ConstrainQuat2Plane(rotation source, vector normal)<br />
{<br />
return llAxisAngle2Rot(normal, <source.x, source.y, source.z> * normal * llRot2Angle(source));<br />
} // Jesrad Seraph</lsl><br />
<br />
// Slerp (rotation combination) function from [[Slerp]]:<br />
<lsl>rotation BlendQuats(rotation a, rotation b, float ratio)<br />
{<br />
return llAxisAngle2Rot(llRot2Axis(b /= a), ratio * llRot2Angle(b)) * a;<br />
}</lsl><br />
<br />
== Constants ==<br />
=== [[ZERO_ROTATION]] ===<br />
ZERO_ROTATION = <0.0, 0.0, 0.0, 1.0>;<br/><br />
A rotation constant representing a Euler angle of <0.0, 0.0, 0.0>.<br />
<br />
=== [[DEG_TO_RAD]] ===<br />
DEG_TO_RAD = 0.01745329238f;<br/><br />
A float constant that when multiplied by an angle in degrees gives the angle in radians.<br />
<br />
=== [[RAD_TO_DEG]] ===<br />
RAD_TO_DEG = 57.29578f;<br/><br />
A float constant when multiplied by an angle in radians gives the angle in degrees.<br />
<br />
<br />
[[Category:LSL_Types|Rotation]][[Category:LSL_Math]][[Category:LSL_Math/3D]][[Category:LSL Rotation]]</div>Jonno Stromfieldhttps://wiki.secondlife.com/wiki/RotationRotation2009-10-21T14:48:41Z<p>Jonno Stromfield: /* Axis plus Turn Angle */</p>
<hr />
<div>{{LSL Header|ml=*}}{{RightToc}}<br />
==Rotation==<br />
The LSL '''rotation''' type is one of several ways to represent an orientation in 3D. (Note that we try to write the type name in '''bold'''.)<br />
<br />
The '''rotation''' can be viewed as a discrete twist in three dimensional space, and the orientation of an object is how much it has been twisted around from whichever axes we are using - normally the region's axes.<br />
<br />
It is a mathematical object called a {{LSLG|quaternion}}. You can think of a quaternion as four numbers, three of which represent the direction an object is facing and a fourth that represents the object's banking left or right around that direction. The main advantage of using <br />
quaternions is that they are not susceptible to [http://en.wikipedia.org/wiki/Gimbal_Lock gimbal lock]. <br />
For the complex inner workings of quaternion mathematics, see {{LSLG|quaternion}}. <br />
For a list of functions and events related to rotations see {{LSLG|LSL Rotation Synopsis}}.<br />
There is also information about causing textures to rotate in {{LSLG|texture}}s.<br />
<br />
==Other representations==<br />
===Euler vector===<br />
Another way to represent a 3D angle is using three numbers, <X, Y, Z>, which represent the amount which the object is rotated around each axis. This is used in the Edit window, for example, and is generally easy for people to visualize. It is easy to adjust the Rotation <x, y, z> numbers in the Edit window and see how the object behaves. Note that in the Edit window, the numbers are in degrees, that is, a right angle is 90.<br />
<br />
In LSL, these three angles are expressed in [[radians]] instead of degrees, that is, a right angle is PI/2. (A radian is sort of a very fat degree.)<br />
Note that these three numbers are a '''vector''' type and not a '''rotation''' type, though it can represent the same information. This is called the ''Euler'' representation of a 3D angle. In LSL the rotation around z is done first, then around y, and finally around x.<br />
<br />
===Axis plus Angle===<br />
In this method you define an axis of rotation, like defining the axis about which the earth spins, and use that together with the angle of rotation about the axis, which defines the amount of turn, to define the '''rotation'''.<br />
<br />
So if you want to define a '''rotation''' about an axis at 45 degrees in the x-y plane (North West in region coordinates), you'd need to point the axis with the same amount of x and y, but with no z. The axis could be <1.0, 1.0, 0.0>. The absolute size of the numbers defining the axis don’t matter in this representation; <2.0, 2.0, 0.0> would work just as well. The angle of rotation is a separate number given in radians, eg. PI/3 = 60 degrees.<br />
<br />
Like a quaternion this uses four numbers, but it doesn't need to be "normalized".<br />
<br />
===FWD, LEFT, UP=== <br />
Another way to represent the same 3D angle is to use three vectors, showing what the front is pointing at (fwd), what the top is pointing at (up), and what the left side is pointing at (left). Actually, only two of the three are needed, because any two determines the third. <br />
<br />
For good reasons, such as being able to easily combine rotations, the four number version, the quaternion '''rotation''', is better, though perhaps harder for a beginner to grasp. Fortunately it's very seldom necessary to do anything with the actual internal representation of ''rotations'' and there are functions for converting easily back and forth between the three LSL types, and between degrees and radians.<br />
<br />
==Right hand rule==<br />
In LSL all rotations are done according to the '''right hand rule'''. With your right hand, extend the first finger in the direction of the positive direction of the x-axis. Extend your second finger at right angles to your first finger, it will point along the positive y-axis, and your thumb, extended at right angles to both will point along the 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).<br />
<br />
http://en.wikipedia.org/wiki/Right_hand_rule<br />
<br />
Now, don't remove your right hand just yet, there is another use for it, determining the direction of a positive rotation. Make a fist with your right hand, thumb extended and pointing in the positive direction of the axis you are interested in. Your fingers curl around in the direction of positive rotation. Rotations around the X, Y, and Z axis are often referred to as Roll, Pitch, and Yaw, particularly for vehicles.<br />
<br />
[http://en.wikipedia.org/wiki/Tait-Bryan_angles Roll Pitch Yaw]<br />
<br />
== Combining Rotations ==<br />
'<br />
Suppose you have two rotations. ''r1'' is rotate 90 degrees to the left, and ''r2'' is rotate 30 degrees to the right. (Any rotations will work; these are just an example.)<br />
You can combine ''r1'' and ''r2'' to make ''r3'' using the '''*''' operator. It doesn't really multiply them, it ''composes'' them.<br />
<lsl><br />
rotation r3 = r1 * r2;<br />
</lsl><br />
The result in this case is that ''r3'' means rotate 60 degrees to the left.<br />
<br />
In other words, 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. The '''multiply''' operation applies the rotation in the positive direction, the '''divide''' operation does a negative rotation. You can also negate a rotation directly, just negate the s component, e.g. X.s = -X.s.<br />
<br />
Unlike other types such as {{LSLG|float}}, the order in which the operations are done, <br />
[http://en.wikipedia.org/wiki/Commutative non-commutative], is important.<br />
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.<br />
<br />
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.<br />
<br />
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.<br />
<br />
Clearly this is a different result from the first rotation, but the order of rotation is the only thing changed.<br />
<br />
To do a constant rotation you need to define a '''rotation''' value which can be done by creating a {{LSLG|vector}} with the X, Y, Z angles in radians as components (called an Euler angle), then converting that to a '''rotation''' by using the {{LSLG|llEuler2Rot}} function. To go from a rotation to an Euler angle {{LSLG|vector}} use {{LSLG|llRot2Euler}}.<br />
<br />
If you want an axial rotation you insert the axis of rotation and the turn angle into the {{LSLG|llAxisAngle2Rot}} function, and this will return the '''rotation'''. To go from a rotation back to axis and angle, use {{LSLG|llRot2Axis}} and {{LSLG|llRot2Angle}} respectively.<br />
<br />
You can alternately create the native rotation directly: the real part is the cosine of half the angle of rotation, and the vector part is the normalized axis of rotation multiplied by the sine of half the angle of rotation.<br />
<br />
'''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:<br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rot30X<br />
| style="white-space: nowrap" |= [[llEuler2Rot]](<30, 0, 0> * [[DEG_TO_RAD]]);<br />
||// convert the degrees to radians, then convert that [[vector]] into a rotation, rot30x<br />
|- valign="top"<br />
| style="white-space: nowrap" |[[vector]] vec30X <br />
| style="white-space: nowrap" |= [[llRot2Euler]](rot30X );<br />
||// convert the rotation back to a [[vector]] (the values will be in radians)<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rot30X<br />
| style="white-space: nowrap" |= [[llAxisAngle2Rot]](<1, 0, 0>, 30 * [[DEG_TO_RAD]]);<br />
||// convert the degrees to radians, then convert into a rotation, rot30x<br />
|}<br />
</div></div><br />
<br />
== Differences between math's quaternions and LSL rotations ==<br />
<br />
There are a few differences between LSL and maths that have little consequences while scripting, but that might puzzle people with prior mathematical knowledge. So we thought it would be good to list them here:<br />
<br />
* In LSL, all quaternions are normalized (the dot product of '''R''' by '''R''' is always '''1'''), and therefore represent ways to rotate objects without changing their size. In maths, generic quaternions might be not normalized, and they represent ''affinities'', i.e. a way to rotate '''and''' change the size of objects.<br />
* In LSL, the '''s''' term is the fourth member of the rotation: '''<x, y, z, s>'''. In maths, the '''s''' term, also called "real part", is written as the first coordinate of the quaternion: '''(s, x, y, z)'''.<br />
* Multiplication is written in reverse order in LSL and in maths. In LSL, you would write '''R * S''', where in maths you would write '''S . R'''.<br />
<br />
== Order of rotation for Euler Vectors ==<br />
<br />
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.<br />
<br />
== Local vs Global (World) rotations ==<br />
<br />
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.<br />
<br />
'''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.<br />
<br />
In LSL, the difference between doing a '''local''' or '''global''' rotation is the order the '''rotations''' are evaluated in the statement.<br />
<br />
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. <br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation localRot = <br />
| style="white-space: nowrap" |rot30X * myRot;<br />
||// do a local rotation by multiplying a constant rotation by a world rotation<br />
|}<br />
</div></div><br />
<br />
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.<br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation globalRot <br />
| style="white-space: nowrap" | = myRot * rot30X;<br />
||// do a global rotation by multiplying a world rotation by a constant rotation<br />
|}<br />
</div></div><br />
<br />
== Another way to think about combining rotations ==<br />
<br />
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.<br />
<br />
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.<br />
<br />
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.<br />
<br />
'''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'''.<br />
<br />
==Using Rotations ==<br />
<br />
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 [[float]]s, but there is overhead in unpacking them.<br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rot30X <br />
| style="white-space: nowrap" |= [[llEuler2Rot]](<30, 0, 0> * [[#DEG_TO_RAD|DEG_TO_RAD]] );<br />
||// Create a rotation constant<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rotCopy <br />
| style="white-space: nowrap" |= rot30X;<br />
||// Just copy it into rotCopy, it copies all 4 float components<br />
|- valign="top"<br />
| style="white-space: nowrap" |float X <br />
| style="white-space: nowrap" |= rotCopy.x;<br />
||// Get out the individual components of the rotation<br />
|- valign="top"<br />
| style="white-space: nowrap" |float Y <br />
| style="white-space: nowrap" |= rotCopy.y;<br />
||<br />
|- valign="top"<br />
| style="white-space: nowrap" |float Z <br />
| style="white-space: nowrap" |= rotCopy.z;<br />
||<br />
|- valign="top"<br />
| style="white-space: nowrap" |float S <br />
| style="white-space: nowrap" |= rotCopy.s;<br />
||<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation anotherCopy <br />
| style="white-space: nowrap" |= <X, Y, Z, S>;<br />
||// Make another rotation out of the components<br />
|}<br />
</div></div><br />
<br />
<br />
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.<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rot330X <br />
| style="white-space: nowrap" |= <-rot30X.x, -rot30X.y, -rot30X.z, rot30X.s>;<br />
||// invert a rotation - NOTE the s component isn't negated<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation another330X <br />
| style="white-space: nowrap" |= [[#ZERO_ROTATION|ZERO_ROTATION]] / rot30X;<br />
||// invert a rotation by division, same result as rot330X<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation yetanother330X <br />
| style="white-space: nowrap" |= <rot30X.x, rot30X.y, rot30X.z, -rot30X.s>;<br />
||// not literally the same but works the same.<br />
|}<br />
</div></div><br />
<br />
==Single or Root Prims vs Linked Prims vs Attachments ==<br />
<br />
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.<br />
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.<br />
<br />
{{LSLRotGetSet}}<br />
<br />
==Rotating Vectors ==<br />
<br />
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.<br />
<br />
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 [[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.<br />
=== Position of Object Rotated Around A Relative Point ===<br />
<lsl>rotation vRotArc = llEuler2Rot( <30.0, 0.0, 0.0> * DEG_TO_RAD );<br />
//-- creates a rotation constant, 30 degrees around the X axis<br />
<br />
vector vPosOffset = <0.0, 1.0, 0.0>;<br />
//-- creates an offset one meter in the positive Y direction<br />
<br />
vector vPosRotOffset = vPosOffset * vRotArc;<br />
//-- rotates the offset to get the motion caused by the rotation<br />
<br />
vector vPosOffsetDiff = vPosOffset - vPosRotOffset;<br />
//-- gets the local difference between the current offset and the rotated one<br />
<br />
vector vPosRotDiff = vPosOffsetDiff * llGetRot();<br />
//-- rotates the difference in the offsets to be relative to the global rotation.<br />
<br />
vector vPosNew = llGetPos() + vPosRotDiff;<br />
//-- finds the prims new position by adding the rotated offset difference<br />
<br />
rotation vRotNew = vRotArc * llGetRot();<br />
//-- finds rot to continue facing offset point</lsl><br />
:in application, the same action as:<br />
<lsl>llSetPrimitiveParams( [PRIM_POSITION, llGetPos() + (vPosOffset - vPosOffset * vRotArc) * llGetRot(),<br />
PRIM_ROTATION, vRotArc * llGetRot()] );</lsl><br />
* The above method results in the orbiting object always having the same side facing the center. An alternative that preserves the orbiters rotation is as follows<br />
<lsl>llSetPrimitiveParams( [PRIM_POSITION, llGetPos() + (vPosOffset - vPosOffset * vRotArc) * llGetRot()];<br />
vPosOffset = vPosOffset * vRotArc;</lsl><br />
'''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. Also to get a full orbit, you'll need to repeat the listed steps (in a [[timer]] perhaps).<br />
<br />
=== Position of Relative Point Around Rotated Object ===<br />
To get a point relative to the objects current facing (such as used in rezzors)<br />
<lsl>vector vPosOffset = <0.0, 0.0, 1.0>;<br />
//-- creates an offset one meter in the positive Z direction.<br />
<br />
vector vPosRotOffset = vPosOffset * llGetRot();<br />
//-- rotate the offset to be relative to objects rotation<br />
<br />
vector vPosOffsetIsAt = llGetPos() + vPosRotOffset;<br />
//-- get the region position of the rotated offset</lsl><br />
:in application, the same action as:<br />
<lsl>llRezAtRoot( "Object", llGetPos() + vPosOffset * llGetRot(), ZERO_VECTOR, llGetRot(), 0 );</lsl><br />
<br />
==Useful Snippets==<br />
<lsl>integer IsRotation(string s)<br />
{<br />
list split = llParseString2List(s, [" "], ["<", ">", ","]);<br />
if(llGetListLength(split) != 9)//we must check the list length, or the next test won't work properly.<br />
return 0;<br />
return !((string)((rotation)s) == (string)((rotation)((string)llListInsertList(split, ["-"], 7))));<br />
//it works by trying to flip the sign on the S element of the rotation,<br />
//if it works or breaks the rotation then the values won't match.<br />
//if the rotation was already broken then the sign flip will have no affect and the values will match<br />
//we cast back to string so we can catch negative zero which allows for support of <0,0,0,0><br />
}//Strife Onizuka</lsl><br />
<br />
<br />
// Calculate a point at distance d in the direction the avatar id is facing<br />
<lsl>vector point_in_front_of( key id, float d )<br />
{<br />
list pose = llGetObjectDetails( id, [ OBJECT_POS, OBJECT_ROT ] );<br />
return ( llList2Vector( pose, 0 ) + < d, 0.0, 0.0 > * llList2Rot( pose, 1 ) );<br />
}// Mephistopheles Thalheimer</lsl><br />
<br />
<br />
// Rez an object o at a distance d from the end of the z axis.<br />
// The object is rezzed oriented to the rezzer<br />
<br />
<lsl>rez_object_at_end( string o, float d )<br />
{<br />
vector s = llGetScale();<br />
<br />
if( llGetInventoryType( o ) == INVENTORY_OBJECT )<br />
{<br />
llRezObject( o, llGetPos() + llRot2Up( llGetRot() ) * ( s.z / 2.0 + d ) , ZERO_VECTOR, llGetRot(), 0 );<br />
}<br />
}// Mephistopheles Thalheimer</lsl><br />
<br />
// Useful functions converted to LSL from [http://www.isner.com/tutorials/quatSpells/quaternion_spells_12.htm this page]:<br />
<br />
// Scale a rotation:<br />
<lsl>rotation ScaleQuat(rotation source, float ratio)<br />
{<br />
return llAxisAngle2Rot(llRot2Axis(source), ratio * llRot2Angle(source));<br />
}</lsl><br />
<br />
// Constrain a rotation to a given plane, defined by its normal, this is very useful for vehicles that remain horizontal in turns:<br />
<lsl>rotation ConstrainQuat2Plane(rotation source, vector normal)<br />
{<br />
return llAxisAngle2Rot(normal, <source.x, source.y, source.z> * normal * llRot2Angle(source));<br />
} // Jesrad Seraph</lsl><br />
<br />
// Slerp (rotation combination) function from [[Slerp]]:<br />
<lsl>rotation BlendQuats(rotation a, rotation b, float ratio)<br />
{<br />
return llAxisAngle2Rot(llRot2Axis(b /= a), ratio * llRot2Angle(b)) * a;<br />
}</lsl><br />
<br />
== Constants ==<br />
=== [[ZERO_ROTATION]] ===<br />
ZERO_ROTATION = <0.0, 0.0, 0.0, 1.0>;<br/><br />
A rotation constant representing a Euler angle of <0.0, 0.0, 0.0>.<br />
<br />
=== [[DEG_TO_RAD]] ===<br />
DEG_TO_RAD = 0.01745329238f;<br/><br />
A float constant that when multiplied by an angle in degrees gives the angle in radians.<br />
<br />
=== [[RAD_TO_DEG]] ===<br />
RAD_TO_DEG = 57.29578f;<br/><br />
A float constant when multiplied by an angle in radians gives the angle in degrees.<br />
<br />
<br />
[[Category:LSL_Types|Rotation]][[Category:LSL_Math]][[Category:LSL_Math/3D]][[Category:LSL Rotation]]</div>Jonno Stromfieldhttps://wiki.secondlife.com/wiki/RotationRotation2009-10-21T14:40:45Z<p>Jonno Stromfield: /* Axis plus Turn Angle */</p>
<hr />
<div>{{LSL Header|ml=*}}{{RightToc}}<br />
==Rotation==<br />
The LSL '''rotation''' type is one of several ways to represent an orientation in 3D. (Note that we try to write the type name in '''bold'''.)<br />
<br />
The '''rotation''' can be viewed as a discrete twist in three dimensional space, and the orientation of an object is how much it has been twisted around from whichever axes we are using - normally the region's axes.<br />
<br />
It is a mathematical object called a {{LSLG|quaternion}}. You can think of a quaternion as four numbers, three of which represent the direction an object is facing and a fourth that represents the object's banking left or right around that direction. The main advantage of using <br />
quaternions is that they are not susceptible to [http://en.wikipedia.org/wiki/Gimbal_Lock gimbal lock]. <br />
For the complex inner workings of quaternion mathematics, see {{LSLG|quaternion}}. <br />
For a list of functions and events related to rotations see {{LSLG|LSL Rotation Synopsis}}.<br />
There is also information about causing textures to rotate in {{LSLG|texture}}s.<br />
<br />
==Other representations==<br />
===Euler vector===<br />
Another way to represent a 3D angle is using three numbers, <X, Y, Z>, which represent the amount which the object is rotated around each axis. This is used in the Edit window, for example, and is generally easy for people to visualize. It is easy to adjust the Rotation <x, y, z> numbers in the Edit window and see how the object behaves. Note that in the Edit window, the numbers are in degrees, that is, a right angle is 90.<br />
<br />
In LSL, these three angles are expressed in [[radians]] instead of degrees, that is, a right angle is PI/2. (A radian is sort of a very fat degree.)<br />
Note that these three numbers are a '''vector''' type and not a '''rotation''' type, though it can represent the same information. This is called the ''Euler'' representation of a 3D angle. In LSL the rotation around z is done first, then around y, and finally around x.<br />
<br />
===Axis plus Turn Angle===<br />
In this method you define an axis of rotation, like defining the axis about which the earth spins, and use that together with the amount of turn about the axis to define the '''rotation'''.<br />
<br />
So if you want to define a '''rotation''' about an axis at 45 degrees in the x-y plane, that means you'd need to point the axis with the same amount of x and y, but with no z. The axis could be <1.0, 1.0, 0.0>. The absolute size of the numbers defining the axis don’t matter in this representation; <2.0, 2.0, 0.0> would work just as well. The amount of turn angle is a separate number given in radians, eg. PI/3 = 60 degrees. <br />
<br />
Like a quaternion this uses four numbers, but it doesn't need to be "normalized".<br />
<br />
===FWD, LEFT, UP=== <br />
Another way to represent the same 3D angle is to use three vectors, showing what the front is pointing at (fwd), what the top is pointing at (up), and what the left side is pointing at (left). Actually, only two of the three are needed, because any two determines the third. <br />
<br />
For good reasons, such as being able to easily combine rotations, the four number version, the quaternion '''rotation''', is better, though perhaps harder for a beginner to grasp. Fortunately it's very seldom necessary to do anything with the actual internal representation of ''rotations'' and there are functions for converting easily back and forth between the three LSL types, and between degrees and radians.<br />
<br />
==Right hand rule==<br />
In LSL all rotations are done according to the '''right hand rule'''. With your right hand, extend the first finger in the direction of the positive direction of the x-axis. Extend your second finger at right angles to your first finger, it will point along the positive y-axis, and your thumb, extended at right angles to both will point along the 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).<br />
<br />
http://en.wikipedia.org/wiki/Right_hand_rule<br />
<br />
Now, don't remove your right hand just yet, there is another use for it, determining the direction of a positive rotation. Make a fist with your right hand, thumb extended and pointing in the positive direction of the axis you are interested in. Your fingers curl around in the direction of positive rotation. Rotations around the X, Y, and Z axis are often referred to as Roll, Pitch, and Yaw, particularly for vehicles.<br />
<br />
[http://en.wikipedia.org/wiki/Tait-Bryan_angles Roll Pitch Yaw]<br />
<br />
== Combining Rotations ==<br />
'<br />
Suppose you have two rotations. ''r1'' is rotate 90 degrees to the left, and ''r2'' is rotate 30 degrees to the right. (Any rotations will work; these are just an example.)<br />
You can combine ''r1'' and ''r2'' to make ''r3'' using the '''*''' operator. It doesn't really multiply them, it ''composes'' them.<br />
<lsl><br />
rotation r3 = r1 * r2;<br />
</lsl><br />
The result in this case is that ''r3'' means rotate 60 degrees to the left.<br />
<br />
In other words, 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. The '''multiply''' operation applies the rotation in the positive direction, the '''divide''' operation does a negative rotation. You can also negate a rotation directly, just negate the s component, e.g. X.s = -X.s.<br />
<br />
Unlike other types such as {{LSLG|float}}, the order in which the operations are done, <br />
[http://en.wikipedia.org/wiki/Commutative non-commutative], is important.<br />
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.<br />
<br />
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.<br />
<br />
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.<br />
<br />
Clearly this is a different result from the first rotation, but the order of rotation is the only thing changed.<br />
<br />
To do a constant rotation you need to define a '''rotation''' value which can be done by creating a {{LSLG|vector}} with the X, Y, Z angles in radians as components (called an Euler angle), then converting that to a '''rotation''' by using the {{LSLG|llEuler2Rot}} function. To go from a rotation to an Euler angle {{LSLG|vector}} use {{LSLG|llRot2Euler}}.<br />
<br />
If you want an axial rotation you insert the axis of rotation and the turn angle into the {{LSLG|llAxisAngle2Rot}} function, and this will return the '''rotation'''. To go from a rotation back to axis and angle, use {{LSLG|llRot2Axis}} and {{LSLG|llRot2Angle}} respectively.<br />
<br />
You can alternately create the native rotation directly: the real part is the cosine of half the angle of rotation, and the vector part is the normalized axis of rotation multiplied by the sine of half the angle of rotation.<br />
<br />
'''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:<br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rot30X<br />
| style="white-space: nowrap" |= [[llEuler2Rot]](<30, 0, 0> * [[DEG_TO_RAD]]);<br />
||// convert the degrees to radians, then convert that [[vector]] into a rotation, rot30x<br />
|- valign="top"<br />
| style="white-space: nowrap" |[[vector]] vec30X <br />
| style="white-space: nowrap" |= [[llRot2Euler]](rot30X );<br />
||// convert the rotation back to a [[vector]] (the values will be in radians)<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rot30X<br />
| style="white-space: nowrap" |= [[llAxisAngle2Rot]](<1, 0, 0>, 30 * [[DEG_TO_RAD]]);<br />
||// convert the degrees to radians, then convert into a rotation, rot30x<br />
|}<br />
</div></div><br />
<br />
== Differences between math's quaternions and LSL rotations ==<br />
<br />
There are a few differences between LSL and maths that have little consequences while scripting, but that might puzzle people with prior mathematical knowledge. So we thought it would be good to list them here:<br />
<br />
* In LSL, all quaternions are normalized (the dot product of '''R''' by '''R''' is always '''1'''), and therefore represent ways to rotate objects without changing their size. In maths, generic quaternions might be not normalized, and they represent ''affinities'', i.e. a way to rotate '''and''' change the size of objects.<br />
* In LSL, the '''s''' term is the fourth member of the rotation: '''<x, y, z, s>'''. In maths, the '''s''' term, also called "real part", is written as the first coordinate of the quaternion: '''(s, x, y, z)'''.<br />
* Multiplication is written in reverse order in LSL and in maths. In LSL, you would write '''R * S''', where in maths you would write '''S . R'''.<br />
<br />
== Order of rotation for Euler Vectors ==<br />
<br />
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.<br />
<br />
== Local vs Global (World) rotations ==<br />
<br />
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.<br />
<br />
'''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.<br />
<br />
In LSL, the difference between doing a '''local''' or '''global''' rotation is the order the '''rotations''' are evaluated in the statement.<br />
<br />
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. <br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation localRot = <br />
| style="white-space: nowrap" |rot30X * myRot;<br />
||// do a local rotation by multiplying a constant rotation by a world rotation<br />
|}<br />
</div></div><br />
<br />
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.<br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation globalRot <br />
| style="white-space: nowrap" | = myRot * rot30X;<br />
||// do a global rotation by multiplying a world rotation by a constant rotation<br />
|}<br />
</div></div><br />
<br />
== Another way to think about combining rotations ==<br />
<br />
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.<br />
<br />
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.<br />
<br />
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.<br />
<br />
'''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'''.<br />
<br />
==Using Rotations ==<br />
<br />
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 [[float]]s, but there is overhead in unpacking them.<br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rot30X <br />
| style="white-space: nowrap" |= [[llEuler2Rot]](<30, 0, 0> * [[#DEG_TO_RAD|DEG_TO_RAD]] );<br />
||// Create a rotation constant<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rotCopy <br />
| style="white-space: nowrap" |= rot30X;<br />
||// Just copy it into rotCopy, it copies all 4 float components<br />
|- valign="top"<br />
| style="white-space: nowrap" |float X <br />
| style="white-space: nowrap" |= rotCopy.x;<br />
||// Get out the individual components of the rotation<br />
|- valign="top"<br />
| style="white-space: nowrap" |float Y <br />
| style="white-space: nowrap" |= rotCopy.y;<br />
||<br />
|- valign="top"<br />
| style="white-space: nowrap" |float Z <br />
| style="white-space: nowrap" |= rotCopy.z;<br />
||<br />
|- valign="top"<br />
| style="white-space: nowrap" |float S <br />
| style="white-space: nowrap" |= rotCopy.s;<br />
||<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation anotherCopy <br />
| style="white-space: nowrap" |= <X, Y, Z, S>;<br />
||// Make another rotation out of the components<br />
|}<br />
</div></div><br />
<br />
<br />
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.<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rot330X <br />
| style="white-space: nowrap" |= <-rot30X.x, -rot30X.y, -rot30X.z, rot30X.s>;<br />
||// invert a rotation - NOTE the s component isn't negated<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation another330X <br />
| style="white-space: nowrap" |= [[#ZERO_ROTATION|ZERO_ROTATION]] / rot30X;<br />
||// invert a rotation by division, same result as rot330X<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation yetanother330X <br />
| style="white-space: nowrap" |= <rot30X.x, rot30X.y, rot30X.z, -rot30X.s>;<br />
||// not literally the same but works the same.<br />
|}<br />
</div></div><br />
<br />
==Single or Root Prims vs Linked Prims vs Attachments ==<br />
<br />
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.<br />
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.<br />
<br />
{{LSLRotGetSet}}<br />
<br />
==Rotating Vectors ==<br />
<br />
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.<br />
<br />
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 [[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.<br />
=== Position of Object Rotated Around A Relative Point ===<br />
<lsl>rotation vRotArc = llEuler2Rot( <30.0, 0.0, 0.0> * DEG_TO_RAD );<br />
//-- creates a rotation constant, 30 degrees around the X axis<br />
<br />
vector vPosOffset = <0.0, 1.0, 0.0>;<br />
//-- creates an offset one meter in the positive Y direction<br />
<br />
vector vPosRotOffset = vPosOffset * vRotArc;<br />
//-- rotates the offset to get the motion caused by the rotation<br />
<br />
vector vPosOffsetDiff = vPosOffset - vPosRotOffset;<br />
//-- gets the local difference between the current offset and the rotated one<br />
<br />
vector vPosRotDiff = vPosOffsetDiff * llGetRot();<br />
//-- rotates the difference in the offsets to be relative to the global rotation.<br />
<br />
vector vPosNew = llGetPos() + vPosRotDiff;<br />
//-- finds the prims new position by adding the rotated offset difference<br />
<br />
rotation vRotNew = vRotArc * llGetRot();<br />
//-- finds rot to continue facing offset point</lsl><br />
:in application, the same action as:<br />
<lsl>llSetPrimitiveParams( [PRIM_POSITION, llGetPos() + (vPosOffset - vPosOffset * vRotArc) * llGetRot(),<br />
PRIM_ROTATION, vRotArc * llGetRot()] );</lsl><br />
* The above method results in the orbiting object always having the same side facing the center. An alternative that preserves the orbiters rotation is as follows<br />
<lsl>llSetPrimitiveParams( [PRIM_POSITION, llGetPos() + (vPosOffset - vPosOffset * vRotArc) * llGetRot()];<br />
vPosOffset = vPosOffset * vRotArc;</lsl><br />
'''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. Also to get a full orbit, you'll need to repeat the listed steps (in a [[timer]] perhaps).<br />
<br />
=== Position of Relative Point Around Rotated Object ===<br />
To get a point relative to the objects current facing (such as used in rezzors)<br />
<lsl>vector vPosOffset = <0.0, 0.0, 1.0>;<br />
//-- creates an offset one meter in the positive Z direction.<br />
<br />
vector vPosRotOffset = vPosOffset * llGetRot();<br />
//-- rotate the offset to be relative to objects rotation<br />
<br />
vector vPosOffsetIsAt = llGetPos() + vPosRotOffset;<br />
//-- get the region position of the rotated offset</lsl><br />
:in application, the same action as:<br />
<lsl>llRezAtRoot( "Object", llGetPos() + vPosOffset * llGetRot(), ZERO_VECTOR, llGetRot(), 0 );</lsl><br />
<br />
==Useful Snippets==<br />
<lsl>integer IsRotation(string s)<br />
{<br />
list split = llParseString2List(s, [" "], ["<", ">", ","]);<br />
if(llGetListLength(split) != 9)//we must check the list length, or the next test won't work properly.<br />
return 0;<br />
return !((string)((rotation)s) == (string)((rotation)((string)llListInsertList(split, ["-"], 7))));<br />
//it works by trying to flip the sign on the S element of the rotation,<br />
//if it works or breaks the rotation then the values won't match.<br />
//if the rotation was already broken then the sign flip will have no affect and the values will match<br />
//we cast back to string so we can catch negative zero which allows for support of <0,0,0,0><br />
}//Strife Onizuka</lsl><br />
<br />
<br />
// Calculate a point at distance d in the direction the avatar id is facing<br />
<lsl>vector point_in_front_of( key id, float d )<br />
{<br />
list pose = llGetObjectDetails( id, [ OBJECT_POS, OBJECT_ROT ] );<br />
return ( llList2Vector( pose, 0 ) + < d, 0.0, 0.0 > * llList2Rot( pose, 1 ) );<br />
}// Mephistopheles Thalheimer</lsl><br />
<br />
<br />
// Rez an object o at a distance d from the end of the z axis.<br />
// The object is rezzed oriented to the rezzer<br />
<br />
<lsl>rez_object_at_end( string o, float d )<br />
{<br />
vector s = llGetScale();<br />
<br />
if( llGetInventoryType( o ) == INVENTORY_OBJECT )<br />
{<br />
llRezObject( o, llGetPos() + llRot2Up( llGetRot() ) * ( s.z / 2.0 + d ) , ZERO_VECTOR, llGetRot(), 0 );<br />
}<br />
}// Mephistopheles Thalheimer</lsl><br />
<br />
// Useful functions converted to LSL from [http://www.isner.com/tutorials/quatSpells/quaternion_spells_12.htm this page]:<br />
<br />
// Scale a rotation:<br />
<lsl>rotation ScaleQuat(rotation source, float ratio)<br />
{<br />
return llAxisAngle2Rot(llRot2Axis(source), ratio * llRot2Angle(source));<br />
}</lsl><br />
<br />
// Constrain a rotation to a given plane, defined by its normal, this is very useful for vehicles that remain horizontal in turns:<br />
<lsl>rotation ConstrainQuat2Plane(rotation source, vector normal)<br />
{<br />
return llAxisAngle2Rot(normal, <source.x, source.y, source.z> * normal * llRot2Angle(source));<br />
} // Jesrad Seraph</lsl><br />
<br />
// Slerp (rotation combination) function from [[Slerp]]:<br />
<lsl>rotation BlendQuats(rotation a, rotation b, float ratio)<br />
{<br />
return llAxisAngle2Rot(llRot2Axis(b /= a), ratio * llRot2Angle(b)) * a;<br />
}</lsl><br />
<br />
== Constants ==<br />
=== [[ZERO_ROTATION]] ===<br />
ZERO_ROTATION = <0.0, 0.0, 0.0, 1.0>;<br/><br />
A rotation constant representing a Euler angle of <0.0, 0.0, 0.0>.<br />
<br />
=== [[DEG_TO_RAD]] ===<br />
DEG_TO_RAD = 0.01745329238f;<br/><br />
A float constant that when multiplied by an angle in degrees gives the angle in radians.<br />
<br />
=== [[RAD_TO_DEG]] ===<br />
RAD_TO_DEG = 57.29578f;<br/><br />
A float constant when multiplied by an angle in radians gives the angle in degrees.<br />
<br />
<br />
[[Category:LSL_Types|Rotation]][[Category:LSL_Math]][[Category:LSL_Math/3D]][[Category:LSL Rotation]]</div>Jonno Stromfieldhttps://wiki.secondlife.com/wiki/RotationRotation2009-10-21T14:37:57Z<p>Jonno Stromfield: /* Axis plus Turn Angle */</p>
<hr />
<div>{{LSL Header|ml=*}}{{RightToc}}<br />
==Rotation==<br />
The LSL '''rotation''' type is one of several ways to represent an orientation in 3D. (Note that we try to write the type name in '''bold'''.)<br />
<br />
The '''rotation''' can be viewed as a discrete twist in three dimensional space, and the orientation of an object is how much it has been twisted around from whichever axes we are using - normally the region's axes.<br />
<br />
It is a mathematical object called a {{LSLG|quaternion}}. You can think of a quaternion as four numbers, three of which represent the direction an object is facing and a fourth that represents the object's banking left or right around that direction. The main advantage of using <br />
quaternions is that they are not susceptible to [http://en.wikipedia.org/wiki/Gimbal_Lock gimbal lock]. <br />
For the complex inner workings of quaternion mathematics, see {{LSLG|quaternion}}. <br />
For a list of functions and events related to rotations see {{LSLG|LSL Rotation Synopsis}}.<br />
There is also information about causing textures to rotate in {{LSLG|texture}}s.<br />
<br />
==Other representations==<br />
===Euler vector===<br />
Another way to represent a 3D angle is using three numbers, <X, Y, Z>, which represent the amount which the object is rotated around each axis. This is used in the Edit window, for example, and is generally easy for people to visualize. It is easy to adjust the Rotation <x, y, z> numbers in the Edit window and see how the object behaves. Note that in the Edit window, the numbers are in degrees, that is, a right angle is 90.<br />
<br />
In LSL, these three angles are expressed in [[radians]] instead of degrees, that is, a right angle is PI/2. (A radian is sort of a very fat degree.)<br />
Note that these three numbers are a '''vector''' type and not a '''rotation''' type, though it can represent the same information. This is called the ''Euler'' representation of a 3D angle. In LSL the rotation around z is done first, then around y, and finally around x.<br />
<br />
===Axis plus Turn Angle===<br />
In this method you define an axis of rotation, like defining the axis about which the earth spins, and use that together with the amount of turn about the axis to define the '''rotation'''.<br />
<br />
So if you want to define a '''rotation''' about an axis at 45 degrees in the x-y plane, that means you'd need to point the axis with the same amount of x and y, but with no z. The axis could be <1.0, 1.0, 0.0>. The absolute size of the numbers defining the axis don’t matter in this representation; <2.0, 2.0, 0.0> would work just as well. The amount of turn angle is a separate number given in radians, eg. PI/3 = 60 degrees. <br />
<br />
Like a quaternion this uses four numbers, but you don’t have to worry about calculating sizes of the numbers you are using as much.<br />
<br />
===FWD, LEFT, UP=== <br />
Another way to represent the same 3D angle is to use three vectors, showing what the front is pointing at (fwd), what the top is pointing at (up), and what the left side is pointing at (left). Actually, only two of the three are needed, because any two determines the third. <br />
<br />
For good reasons, such as being able to easily combine rotations, the four number version, the quaternion '''rotation''', is better, though perhaps harder for a beginner to grasp. Fortunately it's very seldom necessary to do anything with the actual internal representation of ''rotations'' and there are functions for converting easily back and forth between the three LSL types, and between degrees and radians.<br />
<br />
==Right hand rule==<br />
In LSL all rotations are done according to the '''right hand rule'''. With your right hand, extend the first finger in the direction of the positive direction of the x-axis. Extend your second finger at right angles to your first finger, it will point along the positive y-axis, and your thumb, extended at right angles to both will point along the 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).<br />
<br />
http://en.wikipedia.org/wiki/Right_hand_rule<br />
<br />
Now, don't remove your right hand just yet, there is another use for it, determining the direction of a positive rotation. Make a fist with your right hand, thumb extended and pointing in the positive direction of the axis you are interested in. Your fingers curl around in the direction of positive rotation. Rotations around the X, Y, and Z axis are often referred to as Roll, Pitch, and Yaw, particularly for vehicles.<br />
<br />
[http://en.wikipedia.org/wiki/Tait-Bryan_angles Roll Pitch Yaw]<br />
<br />
== Combining Rotations ==<br />
'<br />
Suppose you have two rotations. ''r1'' is rotate 90 degrees to the left, and ''r2'' is rotate 30 degrees to the right. (Any rotations will work; these are just an example.)<br />
You can combine ''r1'' and ''r2'' to make ''r3'' using the '''*''' operator. It doesn't really multiply them, it ''composes'' them.<br />
<lsl><br />
rotation r3 = r1 * r2;<br />
</lsl><br />
The result in this case is that ''r3'' means rotate 60 degrees to the left.<br />
<br />
In other words, 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. The '''multiply''' operation applies the rotation in the positive direction, the '''divide''' operation does a negative rotation. You can also negate a rotation directly, just negate the s component, e.g. X.s = -X.s.<br />
<br />
Unlike other types such as {{LSLG|float}}, the order in which the operations are done, <br />
[http://en.wikipedia.org/wiki/Commutative non-commutative], is important.<br />
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.<br />
<br />
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.<br />
<br />
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.<br />
<br />
Clearly this is a different result from the first rotation, but the order of rotation is the only thing changed.<br />
<br />
To do a constant rotation you need to define a '''rotation''' value which can be done by creating a {{LSLG|vector}} with the X, Y, Z angles in radians as components (called an Euler angle), then converting that to a '''rotation''' by using the {{LSLG|llEuler2Rot}} function. To go from a rotation to an Euler angle {{LSLG|vector}} use {{LSLG|llRot2Euler}}.<br />
<br />
If you want an axial rotation you insert the axis of rotation and the turn angle into the {{LSLG|llAxisAngle2Rot}} function, and this will return the '''rotation'''. To go from a rotation back to axis and angle, use {{LSLG|llRot2Axis}} and {{LSLG|llRot2Angle}} respectively.<br />
<br />
You can alternately create the native rotation directly: the real part is the cosine of half the angle of rotation, and the vector part is the normalized axis of rotation multiplied by the sine of half the angle of rotation.<br />
<br />
'''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:<br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rot30X<br />
| style="white-space: nowrap" |= [[llEuler2Rot]](<30, 0, 0> * [[DEG_TO_RAD]]);<br />
||// convert the degrees to radians, then convert that [[vector]] into a rotation, rot30x<br />
|- valign="top"<br />
| style="white-space: nowrap" |[[vector]] vec30X <br />
| style="white-space: nowrap" |= [[llRot2Euler]](rot30X );<br />
||// convert the rotation back to a [[vector]] (the values will be in radians)<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rot30X<br />
| style="white-space: nowrap" |= [[llAxisAngle2Rot]](<1, 0, 0>, 30 * [[DEG_TO_RAD]]);<br />
||// convert the degrees to radians, then convert into a rotation, rot30x<br />
|}<br />
</div></div><br />
<br />
== Differences between math's quaternions and LSL rotations ==<br />
<br />
There are a few differences between LSL and maths that have little consequences while scripting, but that might puzzle people with prior mathematical knowledge. So we thought it would be good to list them here:<br />
<br />
* In LSL, all quaternions are normalized (the dot product of '''R''' by '''R''' is always '''1'''), and therefore represent ways to rotate objects without changing their size. In maths, generic quaternions might be not normalized, and they represent ''affinities'', i.e. a way to rotate '''and''' change the size of objects.<br />
* In LSL, the '''s''' term is the fourth member of the rotation: '''<x, y, z, s>'''. In maths, the '''s''' term, also called "real part", is written as the first coordinate of the quaternion: '''(s, x, y, z)'''.<br />
* Multiplication is written in reverse order in LSL and in maths. In LSL, you would write '''R * S''', where in maths you would write '''S . R'''.<br />
<br />
== Order of rotation for Euler Vectors ==<br />
<br />
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.<br />
<br />
== Local vs Global (World) rotations ==<br />
<br />
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.<br />
<br />
'''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.<br />
<br />
In LSL, the difference between doing a '''local''' or '''global''' rotation is the order the '''rotations''' are evaluated in the statement.<br />
<br />
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. <br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation localRot = <br />
| style="white-space: nowrap" |rot30X * myRot;<br />
||// do a local rotation by multiplying a constant rotation by a world rotation<br />
|}<br />
</div></div><br />
<br />
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.<br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation globalRot <br />
| style="white-space: nowrap" | = myRot * rot30X;<br />
||// do a global rotation by multiplying a world rotation by a constant rotation<br />
|}<br />
</div></div><br />
<br />
== Another way to think about combining rotations ==<br />
<br />
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.<br />
<br />
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.<br />
<br />
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.<br />
<br />
'''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'''.<br />
<br />
==Using Rotations ==<br />
<br />
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 [[float]]s, but there is overhead in unpacking them.<br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rot30X <br />
| style="white-space: nowrap" |= [[llEuler2Rot]](<30, 0, 0> * [[#DEG_TO_RAD|DEG_TO_RAD]] );<br />
||// Create a rotation constant<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rotCopy <br />
| style="white-space: nowrap" |= rot30X;<br />
||// Just copy it into rotCopy, it copies all 4 float components<br />
|- valign="top"<br />
| style="white-space: nowrap" |float X <br />
| style="white-space: nowrap" |= rotCopy.x;<br />
||// Get out the individual components of the rotation<br />
|- valign="top"<br />
| style="white-space: nowrap" |float Y <br />
| style="white-space: nowrap" |= rotCopy.y;<br />
||<br />
|- valign="top"<br />
| style="white-space: nowrap" |float Z <br />
| style="white-space: nowrap" |= rotCopy.z;<br />
||<br />
|- valign="top"<br />
| style="white-space: nowrap" |float S <br />
| style="white-space: nowrap" |= rotCopy.s;<br />
||<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation anotherCopy <br />
| style="white-space: nowrap" |= <X, Y, Z, S>;<br />
||// Make another rotation out of the components<br />
|}<br />
</div></div><br />
<br />
<br />
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.<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rot330X <br />
| style="white-space: nowrap" |= <-rot30X.x, -rot30X.y, -rot30X.z, rot30X.s>;<br />
||// invert a rotation - NOTE the s component isn't negated<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation another330X <br />
| style="white-space: nowrap" |= [[#ZERO_ROTATION|ZERO_ROTATION]] / rot30X;<br />
||// invert a rotation by division, same result as rot330X<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation yetanother330X <br />
| style="white-space: nowrap" |= <rot30X.x, rot30X.y, rot30X.z, -rot30X.s>;<br />
||// not literally the same but works the same.<br />
|}<br />
</div></div><br />
<br />
==Single or Root Prims vs Linked Prims vs Attachments ==<br />
<br />
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.<br />
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.<br />
<br />
{{LSLRotGetSet}}<br />
<br />
==Rotating Vectors ==<br />
<br />
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.<br />
<br />
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 [[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.<br />
=== Position of Object Rotated Around A Relative Point ===<br />
<lsl>rotation vRotArc = llEuler2Rot( <30.0, 0.0, 0.0> * DEG_TO_RAD );<br />
//-- creates a rotation constant, 30 degrees around the X axis<br />
<br />
vector vPosOffset = <0.0, 1.0, 0.0>;<br />
//-- creates an offset one meter in the positive Y direction<br />
<br />
vector vPosRotOffset = vPosOffset * vRotArc;<br />
//-- rotates the offset to get the motion caused by the rotation<br />
<br />
vector vPosOffsetDiff = vPosOffset - vPosRotOffset;<br />
//-- gets the local difference between the current offset and the rotated one<br />
<br />
vector vPosRotDiff = vPosOffsetDiff * llGetRot();<br />
//-- rotates the difference in the offsets to be relative to the global rotation.<br />
<br />
vector vPosNew = llGetPos() + vPosRotDiff;<br />
//-- finds the prims new position by adding the rotated offset difference<br />
<br />
rotation vRotNew = vRotArc * llGetRot();<br />
//-- finds rot to continue facing offset point</lsl><br />
:in application, the same action as:<br />
<lsl>llSetPrimitiveParams( [PRIM_POSITION, llGetPos() + (vPosOffset - vPosOffset * vRotArc) * llGetRot(),<br />
PRIM_ROTATION, vRotArc * llGetRot()] );</lsl><br />
* The above method results in the orbiting object always having the same side facing the center. An alternative that preserves the orbiters rotation is as follows<br />
<lsl>llSetPrimitiveParams( [PRIM_POSITION, llGetPos() + (vPosOffset - vPosOffset * vRotArc) * llGetRot()];<br />
vPosOffset = vPosOffset * vRotArc;</lsl><br />
'''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. Also to get a full orbit, you'll need to repeat the listed steps (in a [[timer]] perhaps).<br />
<br />
=== Position of Relative Point Around Rotated Object ===<br />
To get a point relative to the objects current facing (such as used in rezzors)<br />
<lsl>vector vPosOffset = <0.0, 0.0, 1.0>;<br />
//-- creates an offset one meter in the positive Z direction.<br />
<br />
vector vPosRotOffset = vPosOffset * llGetRot();<br />
//-- rotate the offset to be relative to objects rotation<br />
<br />
vector vPosOffsetIsAt = llGetPos() + vPosRotOffset;<br />
//-- get the region position of the rotated offset</lsl><br />
:in application, the same action as:<br />
<lsl>llRezAtRoot( "Object", llGetPos() + vPosOffset * llGetRot(), ZERO_VECTOR, llGetRot(), 0 );</lsl><br />
<br />
==Useful Snippets==<br />
<lsl>integer IsRotation(string s)<br />
{<br />
list split = llParseString2List(s, [" "], ["<", ">", ","]);<br />
if(llGetListLength(split) != 9)//we must check the list length, or the next test won't work properly.<br />
return 0;<br />
return !((string)((rotation)s) == (string)((rotation)((string)llListInsertList(split, ["-"], 7))));<br />
//it works by trying to flip the sign on the S element of the rotation,<br />
//if it works or breaks the rotation then the values won't match.<br />
//if the rotation was already broken then the sign flip will have no affect and the values will match<br />
//we cast back to string so we can catch negative zero which allows for support of <0,0,0,0><br />
}//Strife Onizuka</lsl><br />
<br />
<br />
// Calculate a point at distance d in the direction the avatar id is facing<br />
<lsl>vector point_in_front_of( key id, float d )<br />
{<br />
list pose = llGetObjectDetails( id, [ OBJECT_POS, OBJECT_ROT ] );<br />
return ( llList2Vector( pose, 0 ) + < d, 0.0, 0.0 > * llList2Rot( pose, 1 ) );<br />
}// Mephistopheles Thalheimer</lsl><br />
<br />
<br />
// Rez an object o at a distance d from the end of the z axis.<br />
// The object is rezzed oriented to the rezzer<br />
<br />
<lsl>rez_object_at_end( string o, float d )<br />
{<br />
vector s = llGetScale();<br />
<br />
if( llGetInventoryType( o ) == INVENTORY_OBJECT )<br />
{<br />
llRezObject( o, llGetPos() + llRot2Up( llGetRot() ) * ( s.z / 2.0 + d ) , ZERO_VECTOR, llGetRot(), 0 );<br />
}<br />
}// Mephistopheles Thalheimer</lsl><br />
<br />
// Useful functions converted to LSL from [http://www.isner.com/tutorials/quatSpells/quaternion_spells_12.htm this page]:<br />
<br />
// Scale a rotation:<br />
<lsl>rotation ScaleQuat(rotation source, float ratio)<br />
{<br />
return llAxisAngle2Rot(llRot2Axis(source), ratio * llRot2Angle(source));<br />
}</lsl><br />
<br />
// Constrain a rotation to a given plane, defined by its normal, this is very useful for vehicles that remain horizontal in turns:<br />
<lsl>rotation ConstrainQuat2Plane(rotation source, vector normal)<br />
{<br />
return llAxisAngle2Rot(normal, <source.x, source.y, source.z> * normal * llRot2Angle(source));<br />
} // Jesrad Seraph</lsl><br />
<br />
// Slerp (rotation combination) function from [[Slerp]]:<br />
<lsl>rotation BlendQuats(rotation a, rotation b, float ratio)<br />
{<br />
return llAxisAngle2Rot(llRot2Axis(b /= a), ratio * llRot2Angle(b)) * a;<br />
}</lsl><br />
<br />
== Constants ==<br />
=== [[ZERO_ROTATION]] ===<br />
ZERO_ROTATION = <0.0, 0.0, 0.0, 1.0>;<br/><br />
A rotation constant representing a Euler angle of <0.0, 0.0, 0.0>.<br />
<br />
=== [[DEG_TO_RAD]] ===<br />
DEG_TO_RAD = 0.01745329238f;<br/><br />
A float constant that when multiplied by an angle in degrees gives the angle in radians.<br />
<br />
=== [[RAD_TO_DEG]] ===<br />
RAD_TO_DEG = 57.29578f;<br/><br />
A float constant when multiplied by an angle in radians gives the angle in degrees.<br />
<br />
<br />
[[Category:LSL_Types|Rotation]][[Category:LSL_Math]][[Category:LSL_Math/3D]][[Category:LSL Rotation]]</div>Jonno Stromfieldhttps://wiki.secondlife.com/wiki/RotationRotation2009-10-21T13:04:15Z<p>Jonno Stromfield: /* Rotation */</p>
<hr />
<div>{{LSL Header|ml=*}}{{RightToc}}<br />
==Rotation==<br />
The LSL '''rotation''' type is one of several ways to represent an orientation in 3D. (Note that we try to write the type name in '''bold'''.)<br />
<br />
The '''rotation''' can be viewed as a discrete twist in three dimensional space, and the orientation of an object is how much it has been twisted around from whichever axes we are using - normally the region's axes.<br />
<br />
It is a mathematical object called a {{LSLG|quaternion}}. You can think of a quaternion as four numbers, three of which represent the direction an object is facing and a fourth that represents the object's banking left or right around that direction. The main advantage of using <br />
quaternions is that they are not susceptible to [http://en.wikipedia.org/wiki/Gimbal_Lock gimbal lock]. <br />
For the complex inner workings of quaternion mathematics, see {{LSLG|quaternion}}. <br />
For a list of functions and events related to rotations see {{LSLG|LSL Rotation Synopsis}}.<br />
There is also information about causing textures to rotate in {{LSLG|texture}}s.<br />
<br />
==Other representations==<br />
===Euler vector===<br />
Another way to represent a 3D angle is using three numbers, <X, Y, Z>, which represent the amount which the object is rotated around each axis. This is used in the Edit window, for example, and is generally easy for people to visualize. It is easy to adjust the Rotation <x, y, z> numbers in the Edit window and see how the object behaves. Note that in the Edit window, the numbers are in degrees, that is, a right angle is 90.<br />
<br />
In LSL, these three angles are expressed in [[radians]] instead of degrees, that is, a right angle is PI/2. (A radian is sort of a very fat degree.)<br />
Note that these three numbers are a '''vector''' type and not a '''rotation''' type, though it can represent the same information. This is called the ''Euler'' representation of a 3D angle. In LSL the rotation around z is done first, then around y, and finally around x.<br />
<br />
===Axis plus Turn Angle===<br />
In this method you define an axis of rotation, like defining the axis about which the earth spins, and use that together with the amount of turn about the axis to define the '''rotation'''.<br />
<br />
So if you want to define a '''rotation''' about an axis at 45 degrees in the x-y plane, that means you'd need to point the axis the same amount of x and y, but with no z. The axis could be <1.0, 1.0, 0.0>. The absolute size of the numbers defining the axis don’t matter in this representation; <2.0, 2.0, 0.0> would work just as well. The amount of turn angle is a separate number given in radians, eg. PI/3 = 60 degrees. <br />
<br />
Like a quaternion this uses four numbers, but you don’t have to worry about calculating sizes of the numbers you are using as much.<br />
<br />
===FWD, LEFT, UP=== <br />
Another way to represent the same 3D angle is to use three vectors, showing what the front is pointing at (fwd), what the top is pointing at (up), and what the left side is pointing at (left). Actually, only two of the three are needed, because any two determines the third. <br />
<br />
For good reasons, such as being able to easily combine rotations, the four number version, the quaternion '''rotation''', is better, though perhaps harder for a beginner to grasp. Fortunately it's very seldom necessary to do anything with the actual internal representation of ''rotations'' and there are functions for converting easily back and forth between the three LSL types, and between degrees and radians.<br />
<br />
==Right hand rule==<br />
In LSL all rotations are done according to the '''right hand rule'''. With your right hand, extend the first finger in the direction of the positive direction of the x-axis. Extend your second finger at right angles to your first finger, it will point along the positive y-axis, and your thumb, extended at right angles to both will point along the 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).<br />
<br />
http://en.wikipedia.org/wiki/Right_hand_rule<br />
<br />
Now, don't remove your right hand just yet, there is another use for it, determining the direction of a positive rotation. Make a fist with your right hand, thumb extended and pointing in the positive direction of the axis you are interested in. Your fingers curl around in the direction of positive rotation. Rotations around the X, Y, and Z axis are often referred to as Roll, Pitch, and Yaw, particularly for vehicles.<br />
<br />
[http://en.wikipedia.org/wiki/Tait-Bryan_angles Roll Pitch Yaw]<br />
<br />
== Combining Rotations ==<br />
'<br />
Suppose you have two rotations. ''r1'' is rotate 90 degrees to the left, and ''r2'' is rotate 30 degrees to the right. (Any rotations will work; these are just an example.)<br />
You can combine ''r1'' and ''r2'' to make ''r3'' using the '''*''' operator. It doesn't really multiply them, it ''composes'' them.<br />
<lsl><br />
rotation r3 = r1 * r2;<br />
</lsl><br />
The result in this case is that ''r3'' means rotate 60 degrees to the left.<br />
<br />
In other words, 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. The '''multiply''' operation applies the rotation in the positive direction, the '''divide''' operation does a negative rotation. You can also negate a rotation directly, just negate the s component, e.g. X.s = -X.s.<br />
<br />
Unlike other types such as {{LSLG|float}}, the order in which the operations are done, <br />
[http://en.wikipedia.org/wiki/Commutative non-commutative], is important.<br />
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.<br />
<br />
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.<br />
<br />
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.<br />
<br />
Clearly this is a different result from the first rotation, but the order of rotation is the only thing changed.<br />
<br />
To do a constant rotation you need to define a '''rotation''' value which can be done by creating a {{LSLG|vector}} with the X, Y, Z angles in radians as components (called an Euler angle), then converting that to a '''rotation''' by using the {{LSLG|llEuler2Rot}} function. To go from a rotation to an Euler angle {{LSLG|vector}} use {{LSLG|llRot2Euler}}.<br />
<br />
If you want an axial rotation you insert the axis of rotation and the turn angle into the {{LSLG|llAxisAngle2Rot}} function, and this will return the '''rotation'''. To go from a rotation back to axis and angle, use {{LSLG|llRot2Axis}} and {{LSLG|llRot2Angle}} respectively.<br />
<br />
You can alternately create the native rotation directly: the real part is the cosine of half the angle of rotation, and the vector part is the normalized axis of rotation multiplied by the sine of half the angle of rotation.<br />
<br />
'''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:<br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rot30X<br />
| style="white-space: nowrap" |= [[llEuler2Rot]](<30, 0, 0> * [[DEG_TO_RAD]]);<br />
||// convert the degrees to radians, then convert that [[vector]] into a rotation, rot30x<br />
|- valign="top"<br />
| style="white-space: nowrap" |[[vector]] vec30X <br />
| style="white-space: nowrap" |= [[llRot2Euler]](rot30X );<br />
||// convert the rotation back to a [[vector]] (the values will be in radians)<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rot30X<br />
| style="white-space: nowrap" |= [[llAxisAngle2Rot]](<1, 0, 0>, 30 * [[DEG_TO_RAD]]);<br />
||// convert the degrees to radians, then convert into a rotation, rot30x<br />
|}<br />
</div></div><br />
<br />
== Differences between math's quaternions and LSL rotations ==<br />
<br />
There are a few differences between LSL and maths that have little consequences while scripting, but that might puzzle people with prior mathematical knowledge. So we thought it would be good to list them here:<br />
<br />
* In LSL, all quaternions are normalized (the dot product of '''R''' by '''R''' is always '''1'''), and therefore represent ways to rotate objects without changing their size. In maths, generic quaternions might be not normalized, and they represent ''affinities'', i.e. a way to rotate '''and''' change the size of objects.<br />
* In LSL, the '''s''' term is the fourth member of the rotation: '''<x, y, z, s>'''. In maths, the '''s''' term, also called "real part", is written as the first coordinate of the quaternion: '''(s, x, y, z)'''.<br />
* Multiplication is written in reverse order in LSL and in maths. In LSL, you would write '''R * S''', where in maths you would write '''S . R'''.<br />
<br />
== Order of rotation for Euler Vectors ==<br />
<br />
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.<br />
<br />
== Local vs Global (World) rotations ==<br />
<br />
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.<br />
<br />
'''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.<br />
<br />
In LSL, the difference between doing a '''local''' or '''global''' rotation is the order the '''rotations''' are evaluated in the statement.<br />
<br />
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. <br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation localRot = <br />
| style="white-space: nowrap" |rot30X * myRot;<br />
||// do a local rotation by multiplying a constant rotation by a world rotation<br />
|}<br />
</div></div><br />
<br />
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.<br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation globalRot <br />
| style="white-space: nowrap" | = myRot * rot30X;<br />
||// do a global rotation by multiplying a world rotation by a constant rotation<br />
|}<br />
</div></div><br />
<br />
== Another way to think about combining rotations ==<br />
<br />
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.<br />
<br />
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.<br />
<br />
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.<br />
<br />
'''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'''.<br />
<br />
==Using Rotations ==<br />
<br />
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 [[float]]s, but there is overhead in unpacking them.<br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rot30X <br />
| style="white-space: nowrap" |= [[llEuler2Rot]](<30, 0, 0> * [[#DEG_TO_RAD|DEG_TO_RAD]] );<br />
||// Create a rotation constant<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rotCopy <br />
| style="white-space: nowrap" |= rot30X;<br />
||// Just copy it into rotCopy, it copies all 4 float components<br />
|- valign="top"<br />
| style="white-space: nowrap" |float X <br />
| style="white-space: nowrap" |= rotCopy.x;<br />
||// Get out the individual components of the rotation<br />
|- valign="top"<br />
| style="white-space: nowrap" |float Y <br />
| style="white-space: nowrap" |= rotCopy.y;<br />
||<br />
|- valign="top"<br />
| style="white-space: nowrap" |float Z <br />
| style="white-space: nowrap" |= rotCopy.z;<br />
||<br />
|- valign="top"<br />
| style="white-space: nowrap" |float S <br />
| style="white-space: nowrap" |= rotCopy.s;<br />
||<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation anotherCopy <br />
| style="white-space: nowrap" |= <X, Y, Z, S>;<br />
||// Make another rotation out of the components<br />
|}<br />
</div></div><br />
<br />
<br />
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.<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rot330X <br />
| style="white-space: nowrap" |= <-rot30X.x, -rot30X.y, -rot30X.z, rot30X.s>;<br />
||// invert a rotation - NOTE the s component isn't negated<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation another330X <br />
| style="white-space: nowrap" |= [[#ZERO_ROTATION|ZERO_ROTATION]] / rot30X;<br />
||// invert a rotation by division, same result as rot330X<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation yetanother330X <br />
| style="white-space: nowrap" |= <rot30X.x, rot30X.y, rot30X.z, -rot30X.s>;<br />
||// not literally the same but works the same.<br />
|}<br />
</div></div><br />
<br />
==Single or Root Prims vs Linked Prims vs Attachments ==<br />
<br />
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.<br />
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.<br />
<br />
{{LSLRotGetSet}}<br />
<br />
==Rotating Vectors ==<br />
<br />
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.<br />
<br />
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 [[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.<br />
=== Position of Object Rotated Around A Relative Point ===<br />
<lsl>rotation vRotArc = llEuler2Rot( <30.0, 0.0, 0.0> * DEG_TO_RAD );<br />
//-- creates a rotation constant, 30 degrees around the X axis<br />
<br />
vector vPosOffset = <0.0, 1.0, 0.0>;<br />
//-- creates an offset one meter in the positive Y direction<br />
<br />
vector vPosRotOffset = vPosOffset * vRotArc;<br />
//-- rotates the offset to get the motion caused by the rotation<br />
<br />
vector vPosOffsetDiff = vPosOffset - vPosRotOffset;<br />
//-- gets the local difference between the current offset and the rotated one<br />
<br />
vector vPosRotDiff = vPosOffsetDiff * llGetRot();<br />
//-- rotates the difference in the offsets to be relative to the global rotation.<br />
<br />
vector vPosNew = llGetPos() + vPosRotDiff;<br />
//-- finds the prims new position by adding the rotated offset difference<br />
<br />
rotation vRotNew = vRotArc * llGetRot();<br />
//-- finds rot to continue facing offset point</lsl><br />
:in application, the same action as:<br />
<lsl>llSetPrimitiveParams( [PRIM_POSITION, llGetPos() + (vPosOffset - vPosOffset * vRotArc) * llGetRot(),<br />
PRIM_ROTATION, vRotArc * llGetRot()] );</lsl><br />
* The above method results in the orbiting object always having the same side facing the center. An alternative that preserves the orbiters rotation is as follows<br />
<lsl>llSetPrimitiveParams( [PRIM_POSITION, llGetPos() + (vPosOffset - vPosOffset * vRotArc) * llGetRot()];<br />
vPosOffset = vPosOffset * vRotArc;</lsl><br />
'''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. Also to get a full orbit, you'll need to repeat the listed steps (in a [[timer]] perhaps).<br />
<br />
=== Position of Relative Point Around Rotated Object ===<br />
To get a point relative to the objects current facing (such as used in rezzors)<br />
<lsl>vector vPosOffset = <0.0, 0.0, 1.0>;<br />
//-- creates an offset one meter in the positive Z direction.<br />
<br />
vector vPosRotOffset = vPosOffset * llGetRot();<br />
//-- rotate the offset to be relative to objects rotation<br />
<br />
vector vPosOffsetIsAt = llGetPos() + vPosRotOffset;<br />
//-- get the region position of the rotated offset</lsl><br />
:in application, the same action as:<br />
<lsl>llRezAtRoot( "Object", llGetPos() + vPosOffset * llGetRot(), ZERO_VECTOR, llGetRot(), 0 );</lsl><br />
<br />
==Useful Snippets==<br />
<lsl>integer IsRotation(string s)<br />
{<br />
list split = llParseString2List(s, [" "], ["<", ">", ","]);<br />
if(llGetListLength(split) != 9)//we must check the list length, or the next test won't work properly.<br />
return 0;<br />
return !((string)((rotation)s) == (string)((rotation)((string)llListInsertList(split, ["-"], 7))));<br />
//it works by trying to flip the sign on the S element of the rotation,<br />
//if it works or breaks the rotation then the values won't match.<br />
//if the rotation was already broken then the sign flip will have no affect and the values will match<br />
//we cast back to string so we can catch negative zero which allows for support of <0,0,0,0><br />
}//Strife Onizuka</lsl><br />
<br />
<br />
// Calculate a point at distance d in the direction the avatar id is facing<br />
<lsl>vector point_in_front_of( key id, float d )<br />
{<br />
list pose = llGetObjectDetails( id, [ OBJECT_POS, OBJECT_ROT ] );<br />
return ( llList2Vector( pose, 0 ) + < d, 0.0, 0.0 > * llList2Rot( pose, 1 ) );<br />
}// Mephistopheles Thalheimer</lsl><br />
<br />
<br />
// Rez an object o at a distance d from the end of the z axis.<br />
// The object is rezzed oriented to the rezzer<br />
<br />
<lsl>rez_object_at_end( string o, float d )<br />
{<br />
vector s = llGetScale();<br />
<br />
if( llGetInventoryType( o ) == INVENTORY_OBJECT )<br />
{<br />
llRezObject( o, llGetPos() + llRot2Up( llGetRot() ) * ( s.z / 2.0 + d ) , ZERO_VECTOR, llGetRot(), 0 );<br />
}<br />
}// Mephistopheles Thalheimer</lsl><br />
<br />
// Useful functions converted to LSL from [http://www.isner.com/tutorials/quatSpells/quaternion_spells_12.htm this page]:<br />
<br />
// Scale a rotation:<br />
<lsl>rotation ScaleQuat(rotation source, float ratio)<br />
{<br />
return llAxisAngle2Rot(llRot2Axis(source), ratio * llRot2Angle(source));<br />
}</lsl><br />
<br />
// Constrain a rotation to a given plane, defined by its normal, this is very useful for vehicles that remain horizontal in turns:<br />
<lsl>rotation ConstrainQuat2Plane(rotation source, vector normal)<br />
{<br />
return llAxisAngle2Rot(normal, <source.x, source.y, source.z> * normal * llRot2Angle(source));<br />
} // Jesrad Seraph</lsl><br />
<br />
// Slerp (rotation combination) function from [[Slerp]]:<br />
<lsl>rotation BlendQuats(rotation a, rotation b, float ratio)<br />
{<br />
return llAxisAngle2Rot(llRot2Axis(b /= a), ratio * llRot2Angle(b)) * a;<br />
}</lsl><br />
<br />
== Constants ==<br />
=== [[ZERO_ROTATION]] ===<br />
ZERO_ROTATION = <0.0, 0.0, 0.0, 1.0>;<br/><br />
A rotation constant representing a Euler angle of <0.0, 0.0, 0.0>.<br />
<br />
=== [[DEG_TO_RAD]] ===<br />
DEG_TO_RAD = 0.01745329238f;<br/><br />
A float constant that when multiplied by an angle in degrees gives the angle in radians.<br />
<br />
=== [[RAD_TO_DEG]] ===<br />
RAD_TO_DEG = 57.29578f;<br/><br />
A float constant when multiplied by an angle in radians gives the angle in degrees.<br />
<br />
<br />
[[Category:LSL_Types|Rotation]][[Category:LSL_Math]][[Category:LSL_Math/3D]][[Category:LSL Rotation]]</div>Jonno Stromfieldhttps://wiki.secondlife.com/wiki/RotationRotation2009-10-21T12:59:36Z<p>Jonno Stromfield: /* Other representations */</p>
<hr />
<div>{{LSL Header|ml=*}}{{RightToc}}<br />
==Rotation==<br />
The LSL '''rotation''' type is one of several ways to represent an orientation in 3D. (Note that we try to write the type name in '''bold'''.)<br />
<br />
The '''rotation''' can be viewed as a discrete twist in three dimensional space, and the orientation of an object is how much it has been twisted round from whichever axes we are using - normally the region's axes.<br />
<br />
It is a mathematical object called a {{LSLG|quaternion}}. You can think of a quaternion as four numbers, three of which represent the direction an object is facing and a fourth that represents the object's banking left or right around that direction. The main advantage of using <br />
quaternions is that they are not susceptible to [http://en.wikipedia.org/wiki/Gimbal_Lock gimbal lock]. <br />
For the complex inner workings of quaternion mathematics, see {{LSLG|quaternion}}. <br />
For a list of functions and events related to rotations see {{LSLG|LSL Rotation Synopsis}}.<br />
There is also information about causing textures to rotate in {{LSLG|texture}}s.<br />
<br />
==Other representations==<br />
===Euler vector===<br />
Another way to represent a 3D angle is using three numbers, <X, Y, Z>, which represent the amount which the object is rotated around each axis. This is used in the Edit window, for example, and is generally easy for people to visualize. It is easy to adjust the Rotation <x, y, z> numbers in the Edit window and see how the object behaves. Note that in the Edit window, the numbers are in degrees, that is, a right angle is 90.<br />
<br />
In LSL, these three angles are expressed in [[radians]] instead of degrees, that is, a right angle is PI/2. (A radian is sort of a very fat degree.)<br />
Note that these three numbers are a '''vector''' type and not a '''rotation''' type, though it can represent the same information. This is called the ''Euler'' representation of a 3D angle. In LSL the rotation around z is done first, then around y, and finally around x.<br />
<br />
===Axis plus Turn Angle===<br />
In this method you define an axis of rotation, like defining the axis about which the earth spins, and use that together with the amount of turn about the axis to define the '''rotation'''.<br />
<br />
So if you want to define a '''rotation''' about an axis at 45 degrees in the x-y plane, that means you'd need to point the axis the same amount of x and y, but with no z. The axis could be <1.0, 1.0, 0.0>. The absolute size of the numbers defining the axis don’t matter in this representation; <2.0, 2.0, 0.0> would work just as well. The amount of turn angle is a separate number given in radians, eg. PI/3 = 60 degrees. <br />
<br />
Like a quaternion this uses four numbers, but you don’t have to worry about calculating sizes of the numbers you are using as much.<br />
<br />
===FWD, LEFT, UP=== <br />
Another way to represent the same 3D angle is to use three vectors, showing what the front is pointing at (fwd), what the top is pointing at (up), and what the left side is pointing at (left). Actually, only two of the three are needed, because any two determines the third. <br />
<br />
For good reasons, such as being able to easily combine rotations, the four number version, the quaternion '''rotation''', is better, though perhaps harder for a beginner to grasp. Fortunately it's very seldom necessary to do anything with the actual internal representation of ''rotations'' and there are functions for converting easily back and forth between the three LSL types, and between degrees and radians.<br />
<br />
==Right hand rule==<br />
In LSL all rotations are done according to the '''right hand rule'''. With your right hand, extend the first finger in the direction of the positive direction of the x-axis. Extend your second finger at right angles to your first finger, it will point along the positive y-axis, and your thumb, extended at right angles to both will point along the 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).<br />
<br />
http://en.wikipedia.org/wiki/Right_hand_rule<br />
<br />
Now, don't remove your right hand just yet, there is another use for it, determining the direction of a positive rotation. Make a fist with your right hand, thumb extended and pointing in the positive direction of the axis you are interested in. Your fingers curl around in the direction of positive rotation. Rotations around the X, Y, and Z axis are often referred to as Roll, Pitch, and Yaw, particularly for vehicles.<br />
<br />
[http://en.wikipedia.org/wiki/Tait-Bryan_angles Roll Pitch Yaw]<br />
<br />
== Combining Rotations ==<br />
'<br />
Suppose you have two rotations. ''r1'' is rotate 90 degrees to the left, and ''r2'' is rotate 30 degrees to the right. (Any rotations will work; these are just an example.)<br />
You can combine ''r1'' and ''r2'' to make ''r3'' using the '''*''' operator. It doesn't really multiply them, it ''composes'' them.<br />
<lsl><br />
rotation r3 = r1 * r2;<br />
</lsl><br />
The result in this case is that ''r3'' means rotate 60 degrees to the left.<br />
<br />
In other words, 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. The '''multiply''' operation applies the rotation in the positive direction, the '''divide''' operation does a negative rotation. You can also negate a rotation directly, just negate the s component, e.g. X.s = -X.s.<br />
<br />
Unlike other types such as {{LSLG|float}}, the order in which the operations are done, <br />
[http://en.wikipedia.org/wiki/Commutative non-commutative], is important.<br />
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.<br />
<br />
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.<br />
<br />
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.<br />
<br />
Clearly this is a different result from the first rotation, but the order of rotation is the only thing changed.<br />
<br />
To do a constant rotation you need to define a '''rotation''' value which can be done by creating a {{LSLG|vector}} with the X, Y, Z angles in radians as components (called an Euler angle), then converting that to a '''rotation''' by using the {{LSLG|llEuler2Rot}} function. To go from a rotation to an Euler angle {{LSLG|vector}} use {{LSLG|llRot2Euler}}.<br />
<br />
If you want an axial rotation you insert the axis of rotation and the turn angle into the {{LSLG|llAxisAngle2Rot}} function, and this will return the '''rotation'''. To go from a rotation back to axis and angle, use {{LSLG|llRot2Axis}} and {{LSLG|llRot2Angle}} respectively.<br />
<br />
You can alternately create the native rotation directly: the real part is the cosine of half the angle of rotation, and the vector part is the normalized axis of rotation multiplied by the sine of half the angle of rotation.<br />
<br />
'''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:<br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rot30X<br />
| style="white-space: nowrap" |= [[llEuler2Rot]](<30, 0, 0> * [[DEG_TO_RAD]]);<br />
||// convert the degrees to radians, then convert that [[vector]] into a rotation, rot30x<br />
|- valign="top"<br />
| style="white-space: nowrap" |[[vector]] vec30X <br />
| style="white-space: nowrap" |= [[llRot2Euler]](rot30X );<br />
||// convert the rotation back to a [[vector]] (the values will be in radians)<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rot30X<br />
| style="white-space: nowrap" |= [[llAxisAngle2Rot]](<1, 0, 0>, 30 * [[DEG_TO_RAD]]);<br />
||// convert the degrees to radians, then convert into a rotation, rot30x<br />
|}<br />
</div></div><br />
<br />
== Differences between math's quaternions and LSL rotations ==<br />
<br />
There are a few differences between LSL and maths that have little consequences while scripting, but that might puzzle people with prior mathematical knowledge. So we thought it would be good to list them here:<br />
<br />
* In LSL, all quaternions are normalized (the dot product of '''R''' by '''R''' is always '''1'''), and therefore represent ways to rotate objects without changing their size. In maths, generic quaternions might be not normalized, and they represent ''affinities'', i.e. a way to rotate '''and''' change the size of objects.<br />
* In LSL, the '''s''' term is the fourth member of the rotation: '''<x, y, z, s>'''. In maths, the '''s''' term, also called "real part", is written as the first coordinate of the quaternion: '''(s, x, y, z)'''.<br />
* Multiplication is written in reverse order in LSL and in maths. In LSL, you would write '''R * S''', where in maths you would write '''S . R'''.<br />
<br />
== Order of rotation for Euler Vectors ==<br />
<br />
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.<br />
<br />
== Local vs Global (World) rotations ==<br />
<br />
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.<br />
<br />
'''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.<br />
<br />
In LSL, the difference between doing a '''local''' or '''global''' rotation is the order the '''rotations''' are evaluated in the statement.<br />
<br />
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. <br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation localRot = <br />
| style="white-space: nowrap" |rot30X * myRot;<br />
||// do a local rotation by multiplying a constant rotation by a world rotation<br />
|}<br />
</div></div><br />
<br />
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.<br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation globalRot <br />
| style="white-space: nowrap" | = myRot * rot30X;<br />
||// do a global rotation by multiplying a world rotation by a constant rotation<br />
|}<br />
</div></div><br />
<br />
== Another way to think about combining rotations ==<br />
<br />
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.<br />
<br />
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.<br />
<br />
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.<br />
<br />
'''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'''.<br />
<br />
==Using Rotations ==<br />
<br />
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 [[float]]s, but there is overhead in unpacking them.<br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rot30X <br />
| style="white-space: nowrap" |= [[llEuler2Rot]](<30, 0, 0> * [[#DEG_TO_RAD|DEG_TO_RAD]] );<br />
||// Create a rotation constant<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rotCopy <br />
| style="white-space: nowrap" |= rot30X;<br />
||// Just copy it into rotCopy, it copies all 4 float components<br />
|- valign="top"<br />
| style="white-space: nowrap" |float X <br />
| style="white-space: nowrap" |= rotCopy.x;<br />
||// Get out the individual components of the rotation<br />
|- valign="top"<br />
| style="white-space: nowrap" |float Y <br />
| style="white-space: nowrap" |= rotCopy.y;<br />
||<br />
|- valign="top"<br />
| style="white-space: nowrap" |float Z <br />
| style="white-space: nowrap" |= rotCopy.z;<br />
||<br />
|- valign="top"<br />
| style="white-space: nowrap" |float S <br />
| style="white-space: nowrap" |= rotCopy.s;<br />
||<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation anotherCopy <br />
| style="white-space: nowrap" |= <X, Y, Z, S>;<br />
||// Make another rotation out of the components<br />
|}<br />
</div></div><br />
<br />
<br />
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.<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rot330X <br />
| style="white-space: nowrap" |= <-rot30X.x, -rot30X.y, -rot30X.z, rot30X.s>;<br />
||// invert a rotation - NOTE the s component isn't negated<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation another330X <br />
| style="white-space: nowrap" |= [[#ZERO_ROTATION|ZERO_ROTATION]] / rot30X;<br />
||// invert a rotation by division, same result as rot330X<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation yetanother330X <br />
| style="white-space: nowrap" |= <rot30X.x, rot30X.y, rot30X.z, -rot30X.s>;<br />
||// not literally the same but works the same.<br />
|}<br />
</div></div><br />
<br />
==Single or Root Prims vs Linked Prims vs Attachments ==<br />
<br />
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.<br />
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.<br />
<br />
{{LSLRotGetSet}}<br />
<br />
==Rotating Vectors ==<br />
<br />
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.<br />
<br />
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 [[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.<br />
=== Position of Object Rotated Around A Relative Point ===<br />
<lsl>rotation vRotArc = llEuler2Rot( <30.0, 0.0, 0.0> * DEG_TO_RAD );<br />
//-- creates a rotation constant, 30 degrees around the X axis<br />
<br />
vector vPosOffset = <0.0, 1.0, 0.0>;<br />
//-- creates an offset one meter in the positive Y direction<br />
<br />
vector vPosRotOffset = vPosOffset * vRotArc;<br />
//-- rotates the offset to get the motion caused by the rotation<br />
<br />
vector vPosOffsetDiff = vPosOffset - vPosRotOffset;<br />
//-- gets the local difference between the current offset and the rotated one<br />
<br />
vector vPosRotDiff = vPosOffsetDiff * llGetRot();<br />
//-- rotates the difference in the offsets to be relative to the global rotation.<br />
<br />
vector vPosNew = llGetPos() + vPosRotDiff;<br />
//-- finds the prims new position by adding the rotated offset difference<br />
<br />
rotation vRotNew = vRotArc * llGetRot();<br />
//-- finds rot to continue facing offset point</lsl><br />
:in application, the same action as:<br />
<lsl>llSetPrimitiveParams( [PRIM_POSITION, llGetPos() + (vPosOffset - vPosOffset * vRotArc) * llGetRot(),<br />
PRIM_ROTATION, vRotArc * llGetRot()] );</lsl><br />
* The above method results in the orbiting object always having the same side facing the center. An alternative that preserves the orbiters rotation is as follows<br />
<lsl>llSetPrimitiveParams( [PRIM_POSITION, llGetPos() + (vPosOffset - vPosOffset * vRotArc) * llGetRot()];<br />
vPosOffset = vPosOffset * vRotArc;</lsl><br />
'''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. Also to get a full orbit, you'll need to repeat the listed steps (in a [[timer]] perhaps).<br />
<br />
=== Position of Relative Point Around Rotated Object ===<br />
To get a point relative to the objects current facing (such as used in rezzors)<br />
<lsl>vector vPosOffset = <0.0, 0.0, 1.0>;<br />
//-- creates an offset one meter in the positive Z direction.<br />
<br />
vector vPosRotOffset = vPosOffset * llGetRot();<br />
//-- rotate the offset to be relative to objects rotation<br />
<br />
vector vPosOffsetIsAt = llGetPos() + vPosRotOffset;<br />
//-- get the region position of the rotated offset</lsl><br />
:in application, the same action as:<br />
<lsl>llRezAtRoot( "Object", llGetPos() + vPosOffset * llGetRot(), ZERO_VECTOR, llGetRot(), 0 );</lsl><br />
<br />
==Useful Snippets==<br />
<lsl>integer IsRotation(string s)<br />
{<br />
list split = llParseString2List(s, [" "], ["<", ">", ","]);<br />
if(llGetListLength(split) != 9)//we must check the list length, or the next test won't work properly.<br />
return 0;<br />
return !((string)((rotation)s) == (string)((rotation)((string)llListInsertList(split, ["-"], 7))));<br />
//it works by trying to flip the sign on the S element of the rotation,<br />
//if it works or breaks the rotation then the values won't match.<br />
//if the rotation was already broken then the sign flip will have no affect and the values will match<br />
//we cast back to string so we can catch negative zero which allows for support of <0,0,0,0><br />
}//Strife Onizuka</lsl><br />
<br />
<br />
// Calculate a point at distance d in the direction the avatar id is facing<br />
<lsl>vector point_in_front_of( key id, float d )<br />
{<br />
list pose = llGetObjectDetails( id, [ OBJECT_POS, OBJECT_ROT ] );<br />
return ( llList2Vector( pose, 0 ) + < d, 0.0, 0.0 > * llList2Rot( pose, 1 ) );<br />
}// Mephistopheles Thalheimer</lsl><br />
<br />
<br />
// Rez an object o at a distance d from the end of the z axis.<br />
// The object is rezzed oriented to the rezzer<br />
<br />
<lsl>rez_object_at_end( string o, float d )<br />
{<br />
vector s = llGetScale();<br />
<br />
if( llGetInventoryType( o ) == INVENTORY_OBJECT )<br />
{<br />
llRezObject( o, llGetPos() + llRot2Up( llGetRot() ) * ( s.z / 2.0 + d ) , ZERO_VECTOR, llGetRot(), 0 );<br />
}<br />
}// Mephistopheles Thalheimer</lsl><br />
<br />
// Useful functions converted to LSL from [http://www.isner.com/tutorials/quatSpells/quaternion_spells_12.htm this page]:<br />
<br />
// Scale a rotation:<br />
<lsl>rotation ScaleQuat(rotation source, float ratio)<br />
{<br />
return llAxisAngle2Rot(llRot2Axis(source), ratio * llRot2Angle(source));<br />
}</lsl><br />
<br />
// Constrain a rotation to a given plane, defined by its normal, this is very useful for vehicles that remain horizontal in turns:<br />
<lsl>rotation ConstrainQuat2Plane(rotation source, vector normal)<br />
{<br />
return llAxisAngle2Rot(normal, <source.x, source.y, source.z> * normal * llRot2Angle(source));<br />
} // Jesrad Seraph</lsl><br />
<br />
// Slerp (rotation combination) function from [[Slerp]]:<br />
<lsl>rotation BlendQuats(rotation a, rotation b, float ratio)<br />
{<br />
return llAxisAngle2Rot(llRot2Axis(b /= a), ratio * llRot2Angle(b)) * a;<br />
}</lsl><br />
<br />
== Constants ==<br />
=== [[ZERO_ROTATION]] ===<br />
ZERO_ROTATION = <0.0, 0.0, 0.0, 1.0>;<br/><br />
A rotation constant representing a Euler angle of <0.0, 0.0, 0.0>.<br />
<br />
=== [[DEG_TO_RAD]] ===<br />
DEG_TO_RAD = 0.01745329238f;<br/><br />
A float constant that when multiplied by an angle in degrees gives the angle in radians.<br />
<br />
=== [[RAD_TO_DEG]] ===<br />
RAD_TO_DEG = 57.29578f;<br/><br />
A float constant when multiplied by an angle in radians gives the angle in degrees.<br />
<br />
<br />
[[Category:LSL_Types|Rotation]][[Category:LSL_Math]][[Category:LSL_Math/3D]][[Category:LSL Rotation]]</div>Jonno Stromfieldhttps://wiki.secondlife.com/wiki/RotationRotation2009-10-21T12:55:45Z<p>Jonno Stromfield: /* FWD, LEFT, UP */</p>
<hr />
<div>{{LSL Header|ml=*}}{{RightToc}}<br />
==Rotation==<br />
The LSL '''rotation''' type is one of several ways to represent an orientation in 3D. (Note that we try to write the type name in '''bold'''.)<br />
<br />
The '''rotation''' can be viewed as a discrete twist in three dimensional space, and the orientation of an object is how much it has been twisted round from whichever axes we are using - normally the region's axes.<br />
<br />
It is a mathematical object called a {{LSLG|quaternion}}. You can think of a quaternion as four numbers, three of which represent the direction an object is facing and a fourth that represents the object's banking left or right around that direction. The main advantage of using <br />
quaternions is that they are not susceptible to [http://en.wikipedia.org/wiki/Gimbal_Lock gimbal lock]. <br />
For the complex inner workings of quaternion mathematics, see {{LSLG|quaternion}}. <br />
For a list of functions and events related to rotations see {{LSLG|LSL Rotation Synopsis}}.<br />
There is also information about causing textures to rotate in {{LSLG|texture}}s.<br />
<br />
==Other representations==<br />
===Euler vector===<br />
Another way to represent a 3D angle is using three numbers, <X, Y, Z>, which represent the amount which the object is rotated around each axis. This is used in the Edit window, for example, and is generally easy for people to visualize. It is easy to adjust the Rotation <x, y, z> numbers in the Edit window and see how the object behaves. Note that in the Edit window, the numbers are in degrees, that is, a right angle is 90.<br />
<br />
In LSL, these three angles are expressed in [[radians]] instead of degrees, that is, a right angle is PI/2. (A radian is sort of a very fat degree.)<br />
Note that these three numbers are a '''vector''' type and not a '''rotation''' type, though it can represent the same information. This is called the ''Euler'' representation of a 3D angle. In LSL the rotation around z is done first, then around y, and finally around x.<br />
<br />
===Axis plus Turn Angle===<br />
In this method you define an axis of rotation, like defining the axis about which the earth spins, and use that together with the amount of turn about the axis to define the rotation.<br />
<br />
So if you want to define a rotation about an axis at 45 degrees in the x-y plane, that means you'd need the same amount of x and y, but no z. The axis could be <1.0, 1.0, 0.0>. The absolute size of the numbers defining the axis don’t matter in this representation; <2.0, 2.0, 0.0> would work just as well. The amount of turn angle is a separate number given in radians, eg. PI/3 = 60 degrees. <br />
<br />
Like a quaternion this uses four numbers, but you don’t have to worry about calculating sizes of the numbers you are using as much.<br />
<br />
===FWD, LEFT, UP=== <br />
Another way to represent the same 3D angle is to use three vectors, showing what the front is pointing at (fwd), what the top is pointing at (up), and what the left side is pointing at (left). Actually, only two of the three are needed, because any two determines the third. <br />
<br />
For good reasons, such as being able to easily combine rotations, the four number version, the quaternion '''rotation''', is better, though perhaps harder for a beginner to grasp. Fortunately it's very seldom necessary to do anything with the actual internal representation of ''rotations'' and there are functions for converting easily back and forth between the three LSL types, and between degrees and radians.<br />
<br />
==Right hand rule==<br />
In LSL all rotations are done according to the '''right hand rule'''. With your right hand, extend the first finger in the direction of the positive direction of the x-axis. Extend your second finger at right angles to your first finger, it will point along the positive y-axis, and your thumb, extended at right angles to both will point along the 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).<br />
<br />
http://en.wikipedia.org/wiki/Right_hand_rule<br />
<br />
Now, don't remove your right hand just yet, there is another use for it, determining the direction of a positive rotation. Make a fist with your right hand, thumb extended and pointing in the positive direction of the axis you are interested in. Your fingers curl around in the direction of positive rotation. Rotations around the X, Y, and Z axis are often referred to as Roll, Pitch, and Yaw, particularly for vehicles.<br />
<br />
[http://en.wikipedia.org/wiki/Tait-Bryan_angles Roll Pitch Yaw]<br />
<br />
== Combining Rotations ==<br />
'<br />
Suppose you have two rotations. ''r1'' is rotate 90 degrees to the left, and ''r2'' is rotate 30 degrees to the right. (Any rotations will work; these are just an example.)<br />
You can combine ''r1'' and ''r2'' to make ''r3'' using the '''*''' operator. It doesn't really multiply them, it ''composes'' them.<br />
<lsl><br />
rotation r3 = r1 * r2;<br />
</lsl><br />
The result in this case is that ''r3'' means rotate 60 degrees to the left.<br />
<br />
In other words, 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. The '''multiply''' operation applies the rotation in the positive direction, the '''divide''' operation does a negative rotation. You can also negate a rotation directly, just negate the s component, e.g. X.s = -X.s.<br />
<br />
Unlike other types such as {{LSLG|float}}, the order in which the operations are done, <br />
[http://en.wikipedia.org/wiki/Commutative non-commutative], is important.<br />
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.<br />
<br />
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.<br />
<br />
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.<br />
<br />
Clearly this is a different result from the first rotation, but the order of rotation is the only thing changed.<br />
<br />
To do a constant rotation you need to define a '''rotation''' value which can be done by creating a {{LSLG|vector}} with the X, Y, Z angles in radians as components (called an Euler angle), then converting that to a '''rotation''' by using the {{LSLG|llEuler2Rot}} function. To go from a rotation to an Euler angle {{LSLG|vector}} use {{LSLG|llRot2Euler}}.<br />
<br />
If you want an axial rotation you insert the axis of rotation and the turn angle into the {{LSLG|llAxisAngle2Rot}} function, and this will return the '''rotation'''. To go from a rotation back to axis and angle, use {{LSLG|llRot2Axis}} and {{LSLG|llRot2Angle}} respectively.<br />
<br />
You can alternately create the native rotation directly: the real part is the cosine of half the angle of rotation, and the vector part is the normalized axis of rotation multiplied by the sine of half the angle of rotation.<br />
<br />
'''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:<br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rot30X<br />
| style="white-space: nowrap" |= [[llEuler2Rot]](<30, 0, 0> * [[DEG_TO_RAD]]);<br />
||// convert the degrees to radians, then convert that [[vector]] into a rotation, rot30x<br />
|- valign="top"<br />
| style="white-space: nowrap" |[[vector]] vec30X <br />
| style="white-space: nowrap" |= [[llRot2Euler]](rot30X );<br />
||// convert the rotation back to a [[vector]] (the values will be in radians)<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rot30X<br />
| style="white-space: nowrap" |= [[llAxisAngle2Rot]](<1, 0, 0>, 30 * [[DEG_TO_RAD]]);<br />
||// convert the degrees to radians, then convert into a rotation, rot30x<br />
|}<br />
</div></div><br />
<br />
== Differences between math's quaternions and LSL rotations ==<br />
<br />
There are a few differences between LSL and maths that have little consequences while scripting, but that might puzzle people with prior mathematical knowledge. So we thought it would be good to list them here:<br />
<br />
* In LSL, all quaternions are normalized (the dot product of '''R''' by '''R''' is always '''1'''), and therefore represent ways to rotate objects without changing their size. In maths, generic quaternions might be not normalized, and they represent ''affinities'', i.e. a way to rotate '''and''' change the size of objects.<br />
* In LSL, the '''s''' term is the fourth member of the rotation: '''<x, y, z, s>'''. In maths, the '''s''' term, also called "real part", is written as the first coordinate of the quaternion: '''(s, x, y, z)'''.<br />
* Multiplication is written in reverse order in LSL and in maths. In LSL, you would write '''R * S''', where in maths you would write '''S . R'''.<br />
<br />
== Order of rotation for Euler Vectors ==<br />
<br />
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.<br />
<br />
== Local vs Global (World) rotations ==<br />
<br />
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.<br />
<br />
'''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.<br />
<br />
In LSL, the difference between doing a '''local''' or '''global''' rotation is the order the '''rotations''' are evaluated in the statement.<br />
<br />
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. <br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation localRot = <br />
| style="white-space: nowrap" |rot30X * myRot;<br />
||// do a local rotation by multiplying a constant rotation by a world rotation<br />
|}<br />
</div></div><br />
<br />
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.<br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation globalRot <br />
| style="white-space: nowrap" | = myRot * rot30X;<br />
||// do a global rotation by multiplying a world rotation by a constant rotation<br />
|}<br />
</div></div><br />
<br />
== Another way to think about combining rotations ==<br />
<br />
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.<br />
<br />
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.<br />
<br />
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.<br />
<br />
'''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'''.<br />
<br />
==Using Rotations ==<br />
<br />
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 [[float]]s, but there is overhead in unpacking them.<br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rot30X <br />
| style="white-space: nowrap" |= [[llEuler2Rot]](<30, 0, 0> * [[#DEG_TO_RAD|DEG_TO_RAD]] );<br />
||// Create a rotation constant<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rotCopy <br />
| style="white-space: nowrap" |= rot30X;<br />
||// Just copy it into rotCopy, it copies all 4 float components<br />
|- valign="top"<br />
| style="white-space: nowrap" |float X <br />
| style="white-space: nowrap" |= rotCopy.x;<br />
||// Get out the individual components of the rotation<br />
|- valign="top"<br />
| style="white-space: nowrap" |float Y <br />
| style="white-space: nowrap" |= rotCopy.y;<br />
||<br />
|- valign="top"<br />
| style="white-space: nowrap" |float Z <br />
| style="white-space: nowrap" |= rotCopy.z;<br />
||<br />
|- valign="top"<br />
| style="white-space: nowrap" |float S <br />
| style="white-space: nowrap" |= rotCopy.s;<br />
||<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation anotherCopy <br />
| style="white-space: nowrap" |= <X, Y, Z, S>;<br />
||// Make another rotation out of the components<br />
|}<br />
</div></div><br />
<br />
<br />
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.<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rot330X <br />
| style="white-space: nowrap" |= <-rot30X.x, -rot30X.y, -rot30X.z, rot30X.s>;<br />
||// invert a rotation - NOTE the s component isn't negated<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation another330X <br />
| style="white-space: nowrap" |= [[#ZERO_ROTATION|ZERO_ROTATION]] / rot30X;<br />
||// invert a rotation by division, same result as rot330X<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation yetanother330X <br />
| style="white-space: nowrap" |= <rot30X.x, rot30X.y, rot30X.z, -rot30X.s>;<br />
||// not literally the same but works the same.<br />
|}<br />
</div></div><br />
<br />
==Single or Root Prims vs Linked Prims vs Attachments ==<br />
<br />
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.<br />
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.<br />
<br />
{{LSLRotGetSet}}<br />
<br />
==Rotating Vectors ==<br />
<br />
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.<br />
<br />
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 [[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.<br />
=== Position of Object Rotated Around A Relative Point ===<br />
<lsl>rotation vRotArc = llEuler2Rot( <30.0, 0.0, 0.0> * DEG_TO_RAD );<br />
//-- creates a rotation constant, 30 degrees around the X axis<br />
<br />
vector vPosOffset = <0.0, 1.0, 0.0>;<br />
//-- creates an offset one meter in the positive Y direction<br />
<br />
vector vPosRotOffset = vPosOffset * vRotArc;<br />
//-- rotates the offset to get the motion caused by the rotation<br />
<br />
vector vPosOffsetDiff = vPosOffset - vPosRotOffset;<br />
//-- gets the local difference between the current offset and the rotated one<br />
<br />
vector vPosRotDiff = vPosOffsetDiff * llGetRot();<br />
//-- rotates the difference in the offsets to be relative to the global rotation.<br />
<br />
vector vPosNew = llGetPos() + vPosRotDiff;<br />
//-- finds the prims new position by adding the rotated offset difference<br />
<br />
rotation vRotNew = vRotArc * llGetRot();<br />
//-- finds rot to continue facing offset point</lsl><br />
:in application, the same action as:<br />
<lsl>llSetPrimitiveParams( [PRIM_POSITION, llGetPos() + (vPosOffset - vPosOffset * vRotArc) * llGetRot(),<br />
PRIM_ROTATION, vRotArc * llGetRot()] );</lsl><br />
* The above method results in the orbiting object always having the same side facing the center. An alternative that preserves the orbiters rotation is as follows<br />
<lsl>llSetPrimitiveParams( [PRIM_POSITION, llGetPos() + (vPosOffset - vPosOffset * vRotArc) * llGetRot()];<br />
vPosOffset = vPosOffset * vRotArc;</lsl><br />
'''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. Also to get a full orbit, you'll need to repeat the listed steps (in a [[timer]] perhaps).<br />
<br />
=== Position of Relative Point Around Rotated Object ===<br />
To get a point relative to the objects current facing (such as used in rezzors)<br />
<lsl>vector vPosOffset = <0.0, 0.0, 1.0>;<br />
//-- creates an offset one meter in the positive Z direction.<br />
<br />
vector vPosRotOffset = vPosOffset * llGetRot();<br />
//-- rotate the offset to be relative to objects rotation<br />
<br />
vector vPosOffsetIsAt = llGetPos() + vPosRotOffset;<br />
//-- get the region position of the rotated offset</lsl><br />
:in application, the same action as:<br />
<lsl>llRezAtRoot( "Object", llGetPos() + vPosOffset * llGetRot(), ZERO_VECTOR, llGetRot(), 0 );</lsl><br />
<br />
==Useful Snippets==<br />
<lsl>integer IsRotation(string s)<br />
{<br />
list split = llParseString2List(s, [" "], ["<", ">", ","]);<br />
if(llGetListLength(split) != 9)//we must check the list length, or the next test won't work properly.<br />
return 0;<br />
return !((string)((rotation)s) == (string)((rotation)((string)llListInsertList(split, ["-"], 7))));<br />
//it works by trying to flip the sign on the S element of the rotation,<br />
//if it works or breaks the rotation then the values won't match.<br />
//if the rotation was already broken then the sign flip will have no affect and the values will match<br />
//we cast back to string so we can catch negative zero which allows for support of <0,0,0,0><br />
}//Strife Onizuka</lsl><br />
<br />
<br />
// Calculate a point at distance d in the direction the avatar id is facing<br />
<lsl>vector point_in_front_of( key id, float d )<br />
{<br />
list pose = llGetObjectDetails( id, [ OBJECT_POS, OBJECT_ROT ] );<br />
return ( llList2Vector( pose, 0 ) + < d, 0.0, 0.0 > * llList2Rot( pose, 1 ) );<br />
}// Mephistopheles Thalheimer</lsl><br />
<br />
<br />
// Rez an object o at a distance d from the end of the z axis.<br />
// The object is rezzed oriented to the rezzer<br />
<br />
<lsl>rez_object_at_end( string o, float d )<br />
{<br />
vector s = llGetScale();<br />
<br />
if( llGetInventoryType( o ) == INVENTORY_OBJECT )<br />
{<br />
llRezObject( o, llGetPos() + llRot2Up( llGetRot() ) * ( s.z / 2.0 + d ) , ZERO_VECTOR, llGetRot(), 0 );<br />
}<br />
}// Mephistopheles Thalheimer</lsl><br />
<br />
// Useful functions converted to LSL from [http://www.isner.com/tutorials/quatSpells/quaternion_spells_12.htm this page]:<br />
<br />
// Scale a rotation:<br />
<lsl>rotation ScaleQuat(rotation source, float ratio)<br />
{<br />
return llAxisAngle2Rot(llRot2Axis(source), ratio * llRot2Angle(source));<br />
}</lsl><br />
<br />
// Constrain a rotation to a given plane, defined by its normal, this is very useful for vehicles that remain horizontal in turns:<br />
<lsl>rotation ConstrainQuat2Plane(rotation source, vector normal)<br />
{<br />
return llAxisAngle2Rot(normal, <source.x, source.y, source.z> * normal * llRot2Angle(source));<br />
} // Jesrad Seraph</lsl><br />
<br />
// Slerp (rotation combination) function from [[Slerp]]:<br />
<lsl>rotation BlendQuats(rotation a, rotation b, float ratio)<br />
{<br />
return llAxisAngle2Rot(llRot2Axis(b /= a), ratio * llRot2Angle(b)) * a;<br />
}</lsl><br />
<br />
== Constants ==<br />
=== [[ZERO_ROTATION]] ===<br />
ZERO_ROTATION = <0.0, 0.0, 0.0, 1.0>;<br/><br />
A rotation constant representing a Euler angle of <0.0, 0.0, 0.0>.<br />
<br />
=== [[DEG_TO_RAD]] ===<br />
DEG_TO_RAD = 0.01745329238f;<br/><br />
A float constant that when multiplied by an angle in degrees gives the angle in radians.<br />
<br />
=== [[RAD_TO_DEG]] ===<br />
RAD_TO_DEG = 57.29578f;<br/><br />
A float constant when multiplied by an angle in radians gives the angle in degrees.<br />
<br />
<br />
[[Category:LSL_Types|Rotation]][[Category:LSL_Math]][[Category:LSL_Math/3D]][[Category:LSL Rotation]]</div>Jonno Stromfieldhttps://wiki.secondlife.com/wiki/Talk:RotationTalk:Rotation2009-10-21T12:36:50Z<p>Jonno Stromfield: /* Unjustified preference for Euler notation */</p>
<hr />
<div>{{Talk}}<br />
Fixed a few minor syntax errors and reworked the top of the article a bit. As an article it is quite far along though it still has a ways to go. [[User:Strife Onizuka|Strife Onizuka]] 03:32, 29 January 2007 (PST)<br />
<br />
== Intro is awful ==<br />
<br />
"gymbal lock" is something that affects mechanical systems with gyroscopes. A quaternion rotation is a mathematical abstraction. The term simply does not apply, and only serves to confuse things. The reference to "SLERP" without a link is useless. [[User:Doran Zemlja|Doran Zemlja]]<br />
<br />
:Gimbal lock effects Euler angles to which you wrote an article using them everywhere without mention it; it is a gross oversight. That sentence is a bit complex on review and yes there is no SLERP article but that doesn't mean someone won't write one (it is better to leave open links then no links; no links give no hint that a page should be created). I may write a short one tomorrow, I already have a function that implements it (I've just been pressed for time). I will find a better article on gimbal lock, the wikipedia one is pretty poor in this regard as it fails to go into the programing implications. I gave you the benefit of the doubt and looked up 'gymbal' in the dictionary, to which it was nowhere to be found; but 'gimbal' was. [[User:Strife Onizuka|Strife Onizuka]] 19:33, 31 January 2007 (PST)<br />
<br />
::Gimbal lock affects you every time you use Euler Coordinates, it is not restricted to gyroscopes. German article on wikipedia about gimbal lock shows it much more clearly than the English version -- Catherine Pfeffer 2007-12-08<br />
<br />
I'm a mathematician, and think the following text is also misleading (or partially incorrect) in the '''Other Representations''' section: '''''"Another way to represent a rotation is using three numbers, <X, Y, Z>, which represent the amount (in radians) which the object is rotated around each axis. This is used in the Edit window..."''''' Technically, 1 "radian" equals the angle that is traced out by an arc along a circle's circumference, [[when that arc equals the circle's radius]]. This means that 2*pi radians equals 360 degrees, 1*pi radians equals 180 degrees, and pi/2 radians equals 90 degrees. SL's '''prim'''-editing window displays rotations in [[degrees]] (360, 180, 90...) and NOT in [[radians]] (2pi, pi, pi/2)! However, it IS true that radians must be used when editing values in some LSL '''script''' commands! [[User:Times Sands|Times Sands]] 18:18, 10 November 2008 (UTC)<br />
<br />
== Mirroring using quaternions ==<br />
<br />
I think I have worked out how to mirror a point (and therefore an entire object in pieces,) using quaternions, but does anyone here know how to, or if it is even possible to, define a rotation that turns a left hand into a right hand or vise-versa? This is a three diminsional mirror operation, but in four diminsions it is a simple rotation. (I could be wrong, but based on my research into quaternions it seems right...)<br />[[User:Cron Stardust|Cron Stardust]] 22:16, 25 March 2007 (PDT)<br />
:It depends entirely upon which axis you want to mirror around. Save yourself some work and look up Jeffrey's Prim Mirror. [[User:Strife Onizuka|Strife Onizuka]] 11:13, 26 March 2007 (PDT)<br />
<br />
== Moving this page ==<br />
<br />
Shouldn't the content of this page be moved to Category:LSL Rotation? It seems confusing to me to have multiple Rotation pages.<br />
<br />
:Good point, I see no problem merging them. -- [[User:Strife Onizuka|Strife Onizuka]] 08:40, 22 July 2007 (PDT)<br />
<br />
::Very true. Or even better, do a "pure maths" one and a "pure lsl" one -- Catherine Pfeffer, 2007-12-08<br />
<br />
== GetRot()/SetRot() chart ==<br />
<br />
llGetLocalRot() and llGetRot() clearly do *not* return the same value in the root prim of an attachment. While I believe that llGetRot() returns the avatar rotation as indicated, llGetLocalRot() I believe gives the rotation of the root prim relative to the attachment point (or the avatar?)<br />
<br />
:You are correct, that entry in the table is wrong. -- [[User:Strife Onizuka|Strife Onizuka]] 08:40, 22 July 2007 (PDT)<br />
<br />
== Visual aids ==<br />
<br />
I use [http://www.isner.com/tutorials/quatSpells/quaternion_spells_14.htm this page] as a visual reference and cheat sheet for quaternion operations. --[[User:Tateru Nino|Tateru Nino]] 15:53, 9 September 2007 (PDT)<br />
<br />
== Maths versus LSL ==<br />
<br />
Has anyone noticed that maths' quaternion multiplication is written in reverse order than in LSL ? That is, what you write Q1 . Q2 in maths is computed in LSL with Q2 * Q1. Is that a bug or simply a documentation issue ? -- Catherine Pfeffer - 2007-12-08<br />
<br />
:It appears to be a bug, with an obvious patch in the server code, but this bug won't be fixed, so I decided to document the problem here -- Catherine Pfeffer - 2008-08-28<br />
<br />
::I know it's a way late comment, but my guess is that it's the noticable side effect of LSL's backwards order of evaluation. we just don't notice it elsewhere because most other operations within lsl are communicative and quaternion math isn't.<br/>-- '''[[User:Void_Singer|Void]]''' <sup><small>([[User_talk:Void_Singer|talk]]|[[Special:Contributions/Void_Singer|contribs]])</small></sup> 11:09, 19 May 2009 (UTC)<br />
<br />
== Unjustified preference for Euler notation ==<br />
<br />
One thing that really annoys me with this page is that it seems to consider that the Euler coordinates are the easy way to deal with rotations, while the <x, y, z, s> quaternion representation is almost unintelligible.<br />
<br />
That's a common opinon, and as a matter of facts, most LSL scripts I have found use and overuse llEuler2Rot() and llRot2Euler().<br />
<br />
But that's simply wrong. Euler's notation is completly unintuitive for any non-trivial situation.<br />
<br />
To get convinced of it, try to figure out the Euler angles for the rotation of 45 degrees around XY diagonal (X = Y and Z = 0). Good luck ! :-).<br />
Now try figuring out the quaternions's values with the directing vector and sine and cosine of the half-angle: that's straightforward.<br />
<br />
I think this page is misleading a lot of new scripters into the wrong direction because of its preference for Euler angles. -- Catherine Pfeffer - 2008-08-28<br />
<br />
:I agree. '''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 14:19, 28 August 2008 (PDT)<br />
<br />
:As I also agreed and no one here has disagreed, I have take the liberty of adding a section on axis and turn angle. I think it's horses for courses whether you are better off using Euler2Rot or AxisAngle2Rot, but people should be more aware of both. I also put an example in the section on degrees to radians. If anyone wants to champion forward, left, right representation, it won't be me! [[User:Jonno Stromfield|Jonno Stromfield]] 12:21, 21 October 2009 (UTC)<br />
<br />
== Rotating Vectors ==<br />
<br />
The example:-<br />
<br />
//-- same as:<br />
llSetPrimitiveParams( [PRIM_POSITION, llGetPos() + (gPosOffset - gPosOffset * gRotArc) * llGetRot(),PRIM_ROTATION, gRotArc * llGetRot()] );<br />
<br />
gives no derivation of the variables gPosOffset and gRotArc.<br />
Which is less than useful to someone learning from the text.<br />
[[User:Gregory McLeod|Gregory McLeod]] 08:51, 1 September 2008 (PDT)<br />
:missed this comment before. although it should be guessable that offset = gPosOffset, and rot6x = gRotArc, I went ahead and made the section more explicit, and converted it to use lsl highlighting (so that all keywords would be linked) and removed a few slightly misleading viewer frame references. <br/>-- '''[[User:Void_Singer|Void]]''' <sup><small>([[User_talk:Void_Singer|talk]]|[[Special:Contributions/Void_Singer|contribs]])</small></sup> 11:00, 19 May 2009 (UTC)<br />
<br />
== Useful snippets ==<br />
<br />
The snippet we have now is kind of a string function. [http://www.isner.com/tutorials/quatSpells/quaternion_spells_12.htm How about converting these] from XSI to LSL? <br />
<br />
[http://lslwiki.net/lslwiki/wakka.php?wakka=LibraryRotationFunctions How about these] from lslwiki.net? ("All functions on this page are released into public domain and may have been based off other public domain works.")<br />
<br />
By the way, someone above complained about an unlinked reference to slerp() which seems to now be completely missing(!) Both of those have slerp(). [[User:Gia May|Gia May]] 07:15, 8 December 2008 (UTC)<br />
<br />
:I offer L$5000 to the first person who translates two functions from http://www.isner.com/tutorials/quatSpells/quaternion_spells_12.htm to the Useful snippets here, or for code constraining rotations to an arbitrary conic section. Runners up, if any, will be awarded on merit, and I am also asking the Lindens to help with this library deficiency bug bounty. IM me inworld for details. [[User:JS Uralia|JS Uralia]] 21:17, 2 February 2009 (UTC)<br />
::Hello, I went ahead and added three such functions: ConstrainQuaternion2Plane, ScaleQuaternion and CombineQuaternions (Slerp) though this last one already existed on the Wiki.--[[User:Jesrad Seraph|Jesrad Seraph]] 07:05, 17 May 2009 (UTC)<br />
<br />
Pending fulfillment of my promise to pay Jesrad L$5000 -- and [http://wiki.secondlife.com/w/index.php?title=Rotation&diff=220643&oldid=167253 Mephistopheles Thalheimer can attest I keep my word on these bounty payments] -- could someone please independently verify that this function works as it should?<br />
<br />
<lsl>// Constrain a rotation to a given plane, defined by its normal, this is very useful for vehicles that remain horizontal in turns:<br />
rotation ConstrainQuat2Plane(rotation source, vector normal)<br />
{<br />
return llAxisAngle2Rot(normal, <source.x, source.y, source.z> * normal * llRot2Angle(source));<br />
} // Jesrad Seraph</lsl><br />
<br />
I'm very troubled by the use of the first three elements of the quaternion in that manner, but in all honestly, I don't know enough to figure out what a correct answer is. [[User:JS Uralia|JS Uralia]] 20:43, 23 May 2009 (UTC)<br />
<br />
:I think it might just be correct. I can't verify it at the moment but the math looks to have the correct properties though the magnitudes of the vectors going into the dot product worry me. I'm wondering if <source.x, source.y, source.z> shouldn't be normalized first. On a side note, it doesn't handle the edge cases where source and normal haven't been normalized. -- '''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 09:56, 24 May 2009 (UTC)<br />
::More testing shows it is off by sometimes as much as 90 degrees... I will try to correct it, probably by normalizing the vector part first like suggested.--[[User:Jesrad Seraph|Jesrad Seraph]] 14:52, 7 July 2009 (UTC)<br />
<br />
== With regard to rotations of a child of an attachment ==<br />
<br />
I blow a raspberry at lsl. -- '''[[User:EddyFragment Robonaught|Eddy]]''' <sup><small>([[User talk:EddyFragment_Robonaught|talk]]|[[Special:Contributions/EddyFragment_Robonaught|contribs]])</small></sup> 06:37, 13 July 2009 (UTC)<br />
<br />
:Don't you just love {{Jira|SVC-93}}? Gage me with a spoon *rolls eyes*. -- '''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 18:08, 13 July 2009 (UTC)<br />
<br />
Ah. Not just me then. I thought I just needed a degree in quantum maths to understand it. Thanx for the link. *voted* -- '''[[User:EddyFragment Robonaught|Eddy]]''' <sup><small>([[User talk:EddyFragment_Robonaught|talk]]|[[Special:Contributions/EddyFragment_Robonaught|contribs]])</small></sup> 01:41, 14 July 2009 (UTC)<br />
<br />
<br />
I think this is wrong: it claims that the llGetRot of a child prim of an attached object gives "global rotation of avatar * global rotation of prim (Not Useful)" This would be very useful if it were true and would let you calculate the rotation of the attach point. But I think llGetRot gives you the local rotation of the child prim * global rotation of the avatar, which is of no use that I can think of. I'm new at scripting so I'd appreciate some verification and so won't just change the page. [[User:Jonno Stromfield|Jonno Stromfield]] 11:04, 11 September 2009 (UTC)</div>Jonno Stromfieldhttps://wiki.secondlife.com/wiki/Talk:RotationTalk:Rotation2009-10-21T12:35:36Z<p>Jonno Stromfield: /* Unjustified preference for Euler notation */</p>
<hr />
<div>{{Talk}}<br />
Fixed a few minor syntax errors and reworked the top of the article a bit. As an article it is quite far along though it still has a ways to go. [[User:Strife Onizuka|Strife Onizuka]] 03:32, 29 January 2007 (PST)<br />
<br />
== Intro is awful ==<br />
<br />
"gymbal lock" is something that affects mechanical systems with gyroscopes. A quaternion rotation is a mathematical abstraction. The term simply does not apply, and only serves to confuse things. The reference to "SLERP" without a link is useless. [[User:Doran Zemlja|Doran Zemlja]]<br />
<br />
:Gimbal lock effects Euler angles to which you wrote an article using them everywhere without mention it; it is a gross oversight. That sentence is a bit complex on review and yes there is no SLERP article but that doesn't mean someone won't write one (it is better to leave open links then no links; no links give no hint that a page should be created). I may write a short one tomorrow, I already have a function that implements it (I've just been pressed for time). I will find a better article on gimbal lock, the wikipedia one is pretty poor in this regard as it fails to go into the programing implications. I gave you the benefit of the doubt and looked up 'gymbal' in the dictionary, to which it was nowhere to be found; but 'gimbal' was. [[User:Strife Onizuka|Strife Onizuka]] 19:33, 31 January 2007 (PST)<br />
<br />
::Gimbal lock affects you every time you use Euler Coordinates, it is not restricted to gyroscopes. German article on wikipedia about gimbal lock shows it much more clearly than the English version -- Catherine Pfeffer 2007-12-08<br />
<br />
I'm a mathematician, and think the following text is also misleading (or partially incorrect) in the '''Other Representations''' section: '''''"Another way to represent a rotation is using three numbers, <X, Y, Z>, which represent the amount (in radians) which the object is rotated around each axis. This is used in the Edit window..."''''' Technically, 1 "radian" equals the angle that is traced out by an arc along a circle's circumference, [[when that arc equals the circle's radius]]. This means that 2*pi radians equals 360 degrees, 1*pi radians equals 180 degrees, and pi/2 radians equals 90 degrees. SL's '''prim'''-editing window displays rotations in [[degrees]] (360, 180, 90...) and NOT in [[radians]] (2pi, pi, pi/2)! However, it IS true that radians must be used when editing values in some LSL '''script''' commands! [[User:Times Sands|Times Sands]] 18:18, 10 November 2008 (UTC)<br />
<br />
== Mirroring using quaternions ==<br />
<br />
I think I have worked out how to mirror a point (and therefore an entire object in pieces,) using quaternions, but does anyone here know how to, or if it is even possible to, define a rotation that turns a left hand into a right hand or vise-versa? This is a three diminsional mirror operation, but in four diminsions it is a simple rotation. (I could be wrong, but based on my research into quaternions it seems right...)<br />[[User:Cron Stardust|Cron Stardust]] 22:16, 25 March 2007 (PDT)<br />
:It depends entirely upon which axis you want to mirror around. Save yourself some work and look up Jeffrey's Prim Mirror. [[User:Strife Onizuka|Strife Onizuka]] 11:13, 26 March 2007 (PDT)<br />
<br />
== Moving this page ==<br />
<br />
Shouldn't the content of this page be moved to Category:LSL Rotation? It seems confusing to me to have multiple Rotation pages.<br />
<br />
:Good point, I see no problem merging them. -- [[User:Strife Onizuka|Strife Onizuka]] 08:40, 22 July 2007 (PDT)<br />
<br />
::Very true. Or even better, do a "pure maths" one and a "pure lsl" one -- Catherine Pfeffer, 2007-12-08<br />
<br />
== GetRot()/SetRot() chart ==<br />
<br />
llGetLocalRot() and llGetRot() clearly do *not* return the same value in the root prim of an attachment. While I believe that llGetRot() returns the avatar rotation as indicated, llGetLocalRot() I believe gives the rotation of the root prim relative to the attachment point (or the avatar?)<br />
<br />
:You are correct, that entry in the table is wrong. -- [[User:Strife Onizuka|Strife Onizuka]] 08:40, 22 July 2007 (PDT)<br />
<br />
== Visual aids ==<br />
<br />
I use [http://www.isner.com/tutorials/quatSpells/quaternion_spells_14.htm this page] as a visual reference and cheat sheet for quaternion operations. --[[User:Tateru Nino|Tateru Nino]] 15:53, 9 September 2007 (PDT)<br />
<br />
== Maths versus LSL ==<br />
<br />
Has anyone noticed that maths' quaternion multiplication is written in reverse order than in LSL ? That is, what you write Q1 . Q2 in maths is computed in LSL with Q2 * Q1. Is that a bug or simply a documentation issue ? -- Catherine Pfeffer - 2007-12-08<br />
<br />
:It appears to be a bug, with an obvious patch in the server code, but this bug won't be fixed, so I decided to document the problem here -- Catherine Pfeffer - 2008-08-28<br />
<br />
::I know it's a way late comment, but my guess is that it's the noticable side effect of LSL's backwards order of evaluation. we just don't notice it elsewhere because most other operations within lsl are communicative and quaternion math isn't.<br/>-- '''[[User:Void_Singer|Void]]''' <sup><small>([[User_talk:Void_Singer|talk]]|[[Special:Contributions/Void_Singer|contribs]])</small></sup> 11:09, 19 May 2009 (UTC)<br />
<br />
== Unjustified preference for Euler notation ==<br />
<br />
One thing that really annoys me with this page is that it seems to consider that the Euler coordinates are the easy way to deal with rotations, while the <x, y, z, s> quaternion representation is almost unintelligible.<br />
<br />
That's a common opinon, and as a matter of facts, most LSL scripts I have found use and overuse llEuler2Rot() and llRot2Euler().<br />
<br />
But that's simply wrong. Euler's notation is completly unintuitive for any non-trivial situation.<br />
<br />
To get convinced of it, try to figure out the Euler angles for the rotation of 45 degrees around XY diagonal (X = Y and Z = 0). Good luck ! :-).<br />
Now try figuring out the quaternions's values with the directing vector and sine and cosine of the half-angle: that's straightforward.<br />
<br />
I think this page is misleading a lot of new scripters into the wrong direction because of its preference for Euler angles. -- Catherine Pfeffer - 2008-08-28<br />
<br />
:I agree. '''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 14:19, 28 August 2008 (PDT)<br />
<br />
:As I also agreed and no one has disageed here, I have take the liberty of adding a section on axis and turn angle. I think it's horses for courses whether you are better off using Euler2Rot or AxisAngle2Rot, but people should be more aware of both. I also put an example in the section on degrees to radians. If anyone wants to champion forward, left, right representation, it won't be me! [[User:Jonno Stromfield|Jonno Stromfield]] 12:21, 21 October 2009 (UTC)<br />
<br />
== Rotating Vectors ==<br />
<br />
The example:-<br />
<br />
//-- same as:<br />
llSetPrimitiveParams( [PRIM_POSITION, llGetPos() + (gPosOffset - gPosOffset * gRotArc) * llGetRot(),PRIM_ROTATION, gRotArc * llGetRot()] );<br />
<br />
gives no derivation of the variables gPosOffset and gRotArc.<br />
Which is less than useful to someone learning from the text.<br />
[[User:Gregory McLeod|Gregory McLeod]] 08:51, 1 September 2008 (PDT)<br />
:missed this comment before. although it should be guessable that offset = gPosOffset, and rot6x = gRotArc, I went ahead and made the section more explicit, and converted it to use lsl highlighting (so that all keywords would be linked) and removed a few slightly misleading viewer frame references. <br/>-- '''[[User:Void_Singer|Void]]''' <sup><small>([[User_talk:Void_Singer|talk]]|[[Special:Contributions/Void_Singer|contribs]])</small></sup> 11:00, 19 May 2009 (UTC)<br />
<br />
== Useful snippets ==<br />
<br />
The snippet we have now is kind of a string function. [http://www.isner.com/tutorials/quatSpells/quaternion_spells_12.htm How about converting these] from XSI to LSL? <br />
<br />
[http://lslwiki.net/lslwiki/wakka.php?wakka=LibraryRotationFunctions How about these] from lslwiki.net? ("All functions on this page are released into public domain and may have been based off other public domain works.")<br />
<br />
By the way, someone above complained about an unlinked reference to slerp() which seems to now be completely missing(!) Both of those have slerp(). [[User:Gia May|Gia May]] 07:15, 8 December 2008 (UTC)<br />
<br />
:I offer L$5000 to the first person who translates two functions from http://www.isner.com/tutorials/quatSpells/quaternion_spells_12.htm to the Useful snippets here, or for code constraining rotations to an arbitrary conic section. Runners up, if any, will be awarded on merit, and I am also asking the Lindens to help with this library deficiency bug bounty. IM me inworld for details. [[User:JS Uralia|JS Uralia]] 21:17, 2 February 2009 (UTC)<br />
::Hello, I went ahead and added three such functions: ConstrainQuaternion2Plane, ScaleQuaternion and CombineQuaternions (Slerp) though this last one already existed on the Wiki.--[[User:Jesrad Seraph|Jesrad Seraph]] 07:05, 17 May 2009 (UTC)<br />
<br />
Pending fulfillment of my promise to pay Jesrad L$5000 -- and [http://wiki.secondlife.com/w/index.php?title=Rotation&diff=220643&oldid=167253 Mephistopheles Thalheimer can attest I keep my word on these bounty payments] -- could someone please independently verify that this function works as it should?<br />
<br />
<lsl>// Constrain a rotation to a given plane, defined by its normal, this is very useful for vehicles that remain horizontal in turns:<br />
rotation ConstrainQuat2Plane(rotation source, vector normal)<br />
{<br />
return llAxisAngle2Rot(normal, <source.x, source.y, source.z> * normal * llRot2Angle(source));<br />
} // Jesrad Seraph</lsl><br />
<br />
I'm very troubled by the use of the first three elements of the quaternion in that manner, but in all honestly, I don't know enough to figure out what a correct answer is. [[User:JS Uralia|JS Uralia]] 20:43, 23 May 2009 (UTC)<br />
<br />
:I think it might just be correct. I can't verify it at the moment but the math looks to have the correct properties though the magnitudes of the vectors going into the dot product worry me. I'm wondering if <source.x, source.y, source.z> shouldn't be normalized first. On a side note, it doesn't handle the edge cases where source and normal haven't been normalized. -- '''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 09:56, 24 May 2009 (UTC)<br />
::More testing shows it is off by sometimes as much as 90 degrees... I will try to correct it, probably by normalizing the vector part first like suggested.--[[User:Jesrad Seraph|Jesrad Seraph]] 14:52, 7 July 2009 (UTC)<br />
<br />
== With regard to rotations of a child of an attachment ==<br />
<br />
I blow a raspberry at lsl. -- '''[[User:EddyFragment Robonaught|Eddy]]''' <sup><small>([[User talk:EddyFragment_Robonaught|talk]]|[[Special:Contributions/EddyFragment_Robonaught|contribs]])</small></sup> 06:37, 13 July 2009 (UTC)<br />
<br />
:Don't you just love {{Jira|SVC-93}}? Gage me with a spoon *rolls eyes*. -- '''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 18:08, 13 July 2009 (UTC)<br />
<br />
Ah. Not just me then. I thought I just needed a degree in quantum maths to understand it. Thanx for the link. *voted* -- '''[[User:EddyFragment Robonaught|Eddy]]''' <sup><small>([[User talk:EddyFragment_Robonaught|talk]]|[[Special:Contributions/EddyFragment_Robonaught|contribs]])</small></sup> 01:41, 14 July 2009 (UTC)<br />
<br />
<br />
I think this is wrong: it claims that the llGetRot of a child prim of an attached object gives "global rotation of avatar * global rotation of prim (Not Useful)" This would be very useful if it were true and would let you calculate the rotation of the attach point. But I think llGetRot gives you the local rotation of the child prim * global rotation of the avatar, which is of no use that I can think of. I'm new at scripting so I'd appreciate some verification and so won't just change the page. [[User:Jonno Stromfield|Jonno Stromfield]] 11:04, 11 September 2009 (UTC)</div>Jonno Stromfieldhttps://wiki.secondlife.com/wiki/Talk:RotationTalk:Rotation2009-10-21T12:35:06Z<p>Jonno Stromfield: /* Unjustified preference for Euler notation */</p>
<hr />
<div>{{Talk}}<br />
Fixed a few minor syntax errors and reworked the top of the article a bit. As an article it is quite far along though it still has a ways to go. [[User:Strife Onizuka|Strife Onizuka]] 03:32, 29 January 2007 (PST)<br />
<br />
== Intro is awful ==<br />
<br />
"gymbal lock" is something that affects mechanical systems with gyroscopes. A quaternion rotation is a mathematical abstraction. The term simply does not apply, and only serves to confuse things. The reference to "SLERP" without a link is useless. [[User:Doran Zemlja|Doran Zemlja]]<br />
<br />
:Gimbal lock effects Euler angles to which you wrote an article using them everywhere without mention it; it is a gross oversight. That sentence is a bit complex on review and yes there is no SLERP article but that doesn't mean someone won't write one (it is better to leave open links then no links; no links give no hint that a page should be created). I may write a short one tomorrow, I already have a function that implements it (I've just been pressed for time). I will find a better article on gimbal lock, the wikipedia one is pretty poor in this regard as it fails to go into the programing implications. I gave you the benefit of the doubt and looked up 'gymbal' in the dictionary, to which it was nowhere to be found; but 'gimbal' was. [[User:Strife Onizuka|Strife Onizuka]] 19:33, 31 January 2007 (PST)<br />
<br />
::Gimbal lock affects you every time you use Euler Coordinates, it is not restricted to gyroscopes. German article on wikipedia about gimbal lock shows it much more clearly than the English version -- Catherine Pfeffer 2007-12-08<br />
<br />
I'm a mathematician, and think the following text is also misleading (or partially incorrect) in the '''Other Representations''' section: '''''"Another way to represent a rotation is using three numbers, <X, Y, Z>, which represent the amount (in radians) which the object is rotated around each axis. This is used in the Edit window..."''''' Technically, 1 "radian" equals the angle that is traced out by an arc along a circle's circumference, [[when that arc equals the circle's radius]]. This means that 2*pi radians equals 360 degrees, 1*pi radians equals 180 degrees, and pi/2 radians equals 90 degrees. SL's '''prim'''-editing window displays rotations in [[degrees]] (360, 180, 90...) and NOT in [[radians]] (2pi, pi, pi/2)! However, it IS true that radians must be used when editing values in some LSL '''script''' commands! [[User:Times Sands|Times Sands]] 18:18, 10 November 2008 (UTC)<br />
<br />
== Mirroring using quaternions ==<br />
<br />
I think I have worked out how to mirror a point (and therefore an entire object in pieces,) using quaternions, but does anyone here know how to, or if it is even possible to, define a rotation that turns a left hand into a right hand or vise-versa? This is a three diminsional mirror operation, but in four diminsions it is a simple rotation. (I could be wrong, but based on my research into quaternions it seems right...)<br />[[User:Cron Stardust|Cron Stardust]] 22:16, 25 March 2007 (PDT)<br />
:It depends entirely upon which axis you want to mirror around. Save yourself some work and look up Jeffrey's Prim Mirror. [[User:Strife Onizuka|Strife Onizuka]] 11:13, 26 March 2007 (PDT)<br />
<br />
== Moving this page ==<br />
<br />
Shouldn't the content of this page be moved to Category:LSL Rotation? It seems confusing to me to have multiple Rotation pages.<br />
<br />
:Good point, I see no problem merging them. -- [[User:Strife Onizuka|Strife Onizuka]] 08:40, 22 July 2007 (PDT)<br />
<br />
::Very true. Or even better, do a "pure maths" one and a "pure lsl" one -- Catherine Pfeffer, 2007-12-08<br />
<br />
== GetRot()/SetRot() chart ==<br />
<br />
llGetLocalRot() and llGetRot() clearly do *not* return the same value in the root prim of an attachment. While I believe that llGetRot() returns the avatar rotation as indicated, llGetLocalRot() I believe gives the rotation of the root prim relative to the attachment point (or the avatar?)<br />
<br />
:You are correct, that entry in the table is wrong. -- [[User:Strife Onizuka|Strife Onizuka]] 08:40, 22 July 2007 (PDT)<br />
<br />
== Visual aids ==<br />
<br />
I use [http://www.isner.com/tutorials/quatSpells/quaternion_spells_14.htm this page] as a visual reference and cheat sheet for quaternion operations. --[[User:Tateru Nino|Tateru Nino]] 15:53, 9 September 2007 (PDT)<br />
<br />
== Maths versus LSL ==<br />
<br />
Has anyone noticed that maths' quaternion multiplication is written in reverse order than in LSL ? That is, what you write Q1 . Q2 in maths is computed in LSL with Q2 * Q1. Is that a bug or simply a documentation issue ? -- Catherine Pfeffer - 2007-12-08<br />
<br />
:It appears to be a bug, with an obvious patch in the server code, but this bug won't be fixed, so I decided to document the problem here -- Catherine Pfeffer - 2008-08-28<br />
<br />
::I know it's a way late comment, but my guess is that it's the noticable side effect of LSL's backwards order of evaluation. we just don't notice it elsewhere because most other operations within lsl are communicative and quaternion math isn't.<br/>-- '''[[User:Void_Singer|Void]]''' <sup><small>([[User_talk:Void_Singer|talk]]|[[Special:Contributions/Void_Singer|contribs]])</small></sup> 11:09, 19 May 2009 (UTC)<br />
<br />
== Unjustified preference for Euler notation ==<br />
<br />
One thing that really annoys me with this page is that it seems to consider that the Euler coordinates are the easy way to deal with rotations, while the <x, y, z, s> quaternion representation is almost unintelligible.<br />
<br />
That's a common opinon, and as a matter of facts, most LSL scripts I have found use and overuse llEuler2Rot() and llRot2Euler().<br />
<br />
But that's simply wrong. Euler's notation is completly unintuitive for any non-trivial situation.<br />
<br />
To get convinced of it, try to figure out the Euler angles for the rotation of 45 degrees around XY diagonal (X = Y and Z = 0). Good luck ! :-).<br />
Now try figuring out the quaternions's values with the directing vector and sine and cosine of the half-angle: that's straightforward.<br />
<br />
I think this page is misleading a lot of new scripters into the wrong direction because of its preference for Euler angles. -- Catherine Pfeffer - 2008-08-28<br />
<br />
:I agree. '''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 14:19, 28 August 2008 (PDT)<br />
<br />
:As I also agreed and no one has disageed here, I have take the liberty of adding a section on axis and turn angle. I think it's horses for courses whether you are better off using Euler2Rot or AxisAngle2Rot, but people should be more aware of both. I also put an example in the section on degrees to radians. If anyone wants to champion forward, left, right representation, it won't be me!<br />
[[User:Jonno Stromfield|Jonno Stromfield]] 12:21, 21 October 2009 (UTC)<br />
<br />
== Rotating Vectors ==<br />
<br />
The example:-<br />
<br />
//-- same as:<br />
llSetPrimitiveParams( [PRIM_POSITION, llGetPos() + (gPosOffset - gPosOffset * gRotArc) * llGetRot(),PRIM_ROTATION, gRotArc * llGetRot()] );<br />
<br />
gives no derivation of the variables gPosOffset and gRotArc.<br />
Which is less than useful to someone learning from the text.<br />
[[User:Gregory McLeod|Gregory McLeod]] 08:51, 1 September 2008 (PDT)<br />
:missed this comment before. although it should be guessable that offset = gPosOffset, and rot6x = gRotArc, I went ahead and made the section more explicit, and converted it to use lsl highlighting (so that all keywords would be linked) and removed a few slightly misleading viewer frame references. <br/>-- '''[[User:Void_Singer|Void]]''' <sup><small>([[User_talk:Void_Singer|talk]]|[[Special:Contributions/Void_Singer|contribs]])</small></sup> 11:00, 19 May 2009 (UTC)<br />
<br />
== Useful snippets ==<br />
<br />
The snippet we have now is kind of a string function. [http://www.isner.com/tutorials/quatSpells/quaternion_spells_12.htm How about converting these] from XSI to LSL? <br />
<br />
[http://lslwiki.net/lslwiki/wakka.php?wakka=LibraryRotationFunctions How about these] from lslwiki.net? ("All functions on this page are released into public domain and may have been based off other public domain works.")<br />
<br />
By the way, someone above complained about an unlinked reference to slerp() which seems to now be completely missing(!) Both of those have slerp(). [[User:Gia May|Gia May]] 07:15, 8 December 2008 (UTC)<br />
<br />
:I offer L$5000 to the first person who translates two functions from http://www.isner.com/tutorials/quatSpells/quaternion_spells_12.htm to the Useful snippets here, or for code constraining rotations to an arbitrary conic section. Runners up, if any, will be awarded on merit, and I am also asking the Lindens to help with this library deficiency bug bounty. IM me inworld for details. [[User:JS Uralia|JS Uralia]] 21:17, 2 February 2009 (UTC)<br />
::Hello, I went ahead and added three such functions: ConstrainQuaternion2Plane, ScaleQuaternion and CombineQuaternions (Slerp) though this last one already existed on the Wiki.--[[User:Jesrad Seraph|Jesrad Seraph]] 07:05, 17 May 2009 (UTC)<br />
<br />
Pending fulfillment of my promise to pay Jesrad L$5000 -- and [http://wiki.secondlife.com/w/index.php?title=Rotation&diff=220643&oldid=167253 Mephistopheles Thalheimer can attest I keep my word on these bounty payments] -- could someone please independently verify that this function works as it should?<br />
<br />
<lsl>// Constrain a rotation to a given plane, defined by its normal, this is very useful for vehicles that remain horizontal in turns:<br />
rotation ConstrainQuat2Plane(rotation source, vector normal)<br />
{<br />
return llAxisAngle2Rot(normal, <source.x, source.y, source.z> * normal * llRot2Angle(source));<br />
} // Jesrad Seraph</lsl><br />
<br />
I'm very troubled by the use of the first three elements of the quaternion in that manner, but in all honestly, I don't know enough to figure out what a correct answer is. [[User:JS Uralia|JS Uralia]] 20:43, 23 May 2009 (UTC)<br />
<br />
:I think it might just be correct. I can't verify it at the moment but the math looks to have the correct properties though the magnitudes of the vectors going into the dot product worry me. I'm wondering if <source.x, source.y, source.z> shouldn't be normalized first. On a side note, it doesn't handle the edge cases where source and normal haven't been normalized. -- '''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 09:56, 24 May 2009 (UTC)<br />
::More testing shows it is off by sometimes as much as 90 degrees... I will try to correct it, probably by normalizing the vector part first like suggested.--[[User:Jesrad Seraph|Jesrad Seraph]] 14:52, 7 July 2009 (UTC)<br />
<br />
== With regard to rotations of a child of an attachment ==<br />
<br />
I blow a raspberry at lsl. -- '''[[User:EddyFragment Robonaught|Eddy]]''' <sup><small>([[User talk:EddyFragment_Robonaught|talk]]|[[Special:Contributions/EddyFragment_Robonaught|contribs]])</small></sup> 06:37, 13 July 2009 (UTC)<br />
<br />
:Don't you just love {{Jira|SVC-93}}? Gage me with a spoon *rolls eyes*. -- '''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 18:08, 13 July 2009 (UTC)<br />
<br />
Ah. Not just me then. I thought I just needed a degree in quantum maths to understand it. Thanx for the link. *voted* -- '''[[User:EddyFragment Robonaught|Eddy]]''' <sup><small>([[User talk:EddyFragment_Robonaught|talk]]|[[Special:Contributions/EddyFragment_Robonaught|contribs]])</small></sup> 01:41, 14 July 2009 (UTC)<br />
<br />
<br />
I think this is wrong: it claims that the llGetRot of a child prim of an attached object gives "global rotation of avatar * global rotation of prim (Not Useful)" This would be very useful if it were true and would let you calculate the rotation of the attach point. But I think llGetRot gives you the local rotation of the child prim * global rotation of the avatar, which is of no use that I can think of. I'm new at scripting so I'd appreciate some verification and so won't just change the page. [[User:Jonno Stromfield|Jonno Stromfield]] 11:04, 11 September 2009 (UTC)</div>Jonno Stromfieldhttps://wiki.secondlife.com/wiki/Talk:RotationTalk:Rotation2009-10-21T12:21:05Z<p>Jonno Stromfield: /* Unjustified preference for Euler notation */</p>
<hr />
<div>{{Talk}}<br />
Fixed a few minor syntax errors and reworked the top of the article a bit. As an article it is quite far along though it still has a ways to go. [[User:Strife Onizuka|Strife Onizuka]] 03:32, 29 January 2007 (PST)<br />
<br />
== Intro is awful ==<br />
<br />
"gymbal lock" is something that affects mechanical systems with gyroscopes. A quaternion rotation is a mathematical abstraction. The term simply does not apply, and only serves to confuse things. The reference to "SLERP" without a link is useless. [[User:Doran Zemlja|Doran Zemlja]]<br />
<br />
:Gimbal lock effects Euler angles to which you wrote an article using them everywhere without mention it; it is a gross oversight. That sentence is a bit complex on review and yes there is no SLERP article but that doesn't mean someone won't write one (it is better to leave open links then no links; no links give no hint that a page should be created). I may write a short one tomorrow, I already have a function that implements it (I've just been pressed for time). I will find a better article on gimbal lock, the wikipedia one is pretty poor in this regard as it fails to go into the programing implications. I gave you the benefit of the doubt and looked up 'gymbal' in the dictionary, to which it was nowhere to be found; but 'gimbal' was. [[User:Strife Onizuka|Strife Onizuka]] 19:33, 31 January 2007 (PST)<br />
<br />
::Gimbal lock affects you every time you use Euler Coordinates, it is not restricted to gyroscopes. German article on wikipedia about gimbal lock shows it much more clearly than the English version -- Catherine Pfeffer 2007-12-08<br />
<br />
I'm a mathematician, and think the following text is also misleading (or partially incorrect) in the '''Other Representations''' section: '''''"Another way to represent a rotation is using three numbers, <X, Y, Z>, which represent the amount (in radians) which the object is rotated around each axis. This is used in the Edit window..."''''' Technically, 1 "radian" equals the angle that is traced out by an arc along a circle's circumference, [[when that arc equals the circle's radius]]. This means that 2*pi radians equals 360 degrees, 1*pi radians equals 180 degrees, and pi/2 radians equals 90 degrees. SL's '''prim'''-editing window displays rotations in [[degrees]] (360, 180, 90...) and NOT in [[radians]] (2pi, pi, pi/2)! However, it IS true that radians must be used when editing values in some LSL '''script''' commands! [[User:Times Sands|Times Sands]] 18:18, 10 November 2008 (UTC)<br />
<br />
== Mirroring using quaternions ==<br />
<br />
I think I have worked out how to mirror a point (and therefore an entire object in pieces,) using quaternions, but does anyone here know how to, or if it is even possible to, define a rotation that turns a left hand into a right hand or vise-versa? This is a three diminsional mirror operation, but in four diminsions it is a simple rotation. (I could be wrong, but based on my research into quaternions it seems right...)<br />[[User:Cron Stardust|Cron Stardust]] 22:16, 25 March 2007 (PDT)<br />
:It depends entirely upon which axis you want to mirror around. Save yourself some work and look up Jeffrey's Prim Mirror. [[User:Strife Onizuka|Strife Onizuka]] 11:13, 26 March 2007 (PDT)<br />
<br />
== Moving this page ==<br />
<br />
Shouldn't the content of this page be moved to Category:LSL Rotation? It seems confusing to me to have multiple Rotation pages.<br />
<br />
:Good point, I see no problem merging them. -- [[User:Strife Onizuka|Strife Onizuka]] 08:40, 22 July 2007 (PDT)<br />
<br />
::Very true. Or even better, do a "pure maths" one and a "pure lsl" one -- Catherine Pfeffer, 2007-12-08<br />
<br />
== GetRot()/SetRot() chart ==<br />
<br />
llGetLocalRot() and llGetRot() clearly do *not* return the same value in the root prim of an attachment. While I believe that llGetRot() returns the avatar rotation as indicated, llGetLocalRot() I believe gives the rotation of the root prim relative to the attachment point (or the avatar?)<br />
<br />
:You are correct, that entry in the table is wrong. -- [[User:Strife Onizuka|Strife Onizuka]] 08:40, 22 July 2007 (PDT)<br />
<br />
== Visual aids ==<br />
<br />
I use [http://www.isner.com/tutorials/quatSpells/quaternion_spells_14.htm this page] as a visual reference and cheat sheet for quaternion operations. --[[User:Tateru Nino|Tateru Nino]] 15:53, 9 September 2007 (PDT)<br />
<br />
== Maths versus LSL ==<br />
<br />
Has anyone noticed that maths' quaternion multiplication is written in reverse order than in LSL ? That is, what you write Q1 . Q2 in maths is computed in LSL with Q2 * Q1. Is that a bug or simply a documentation issue ? -- Catherine Pfeffer - 2007-12-08<br />
<br />
:It appears to be a bug, with an obvious patch in the server code, but this bug won't be fixed, so I decided to document the problem here -- Catherine Pfeffer - 2008-08-28<br />
<br />
::I know it's a way late comment, but my guess is that it's the noticable side effect of LSL's backwards order of evaluation. we just don't notice it elsewhere because most other operations within lsl are communicative and quaternion math isn't.<br/>-- '''[[User:Void_Singer|Void]]''' <sup><small>([[User_talk:Void_Singer|talk]]|[[Special:Contributions/Void_Singer|contribs]])</small></sup> 11:09, 19 May 2009 (UTC)<br />
<br />
== Unjustified preference for Euler notation ==<br />
<br />
One thing that really annoys me with this page is that it seems to consider that the Euler coordinates are the easy way to deal with rotations, while the <x, y, z, s> quaternion representation is almost unintelligible.<br />
<br />
That's a common opinon, and as a matter of facts, most LSL scripts I have found use and overuse llEuler2Rot() and llRot2Euler().<br />
<br />
But that's simply wrong. Euler's notation is completly unintuitive for any non-trivial situation.<br />
<br />
To get convinced of it, try to figure out the Euler angles for the rotation of 45 degrees around XY diagonal (X = Y and Z = 0). Good luck ! :-).<br />
Now try figuring out the quaternions's values with the directing vector and sine and cosine of the half-angle: that's straightforward.<br />
<br />
I think this page is misleading a lot of new scripters into the wrong direction because of its preference for Euler angles. -- Catherine Pfeffer - 2008-08-28<br />
<br />
:I agree. '''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 14:19, 28 August 2008 (PDT)<br />
<br />
As I also agreed and no one has disageed here, I have take the liberty of adding a section on axis and turn angle. I think it's horses for courses whether you are better off using Euler2Rot or AxisAngle2Rot, but people should be more aware of both. I also put an example in the section on degrees to radians. If anyone wants to champion forward, left, right representation, it won't be me!<br />
[[User:Jonno Stromfield|Jonno Stromfield]] 12:21, 21 October 2009 (UTC)<br />
<br />
== Rotating Vectors ==<br />
<br />
The example:-<br />
<br />
//-- same as:<br />
llSetPrimitiveParams( [PRIM_POSITION, llGetPos() + (gPosOffset - gPosOffset * gRotArc) * llGetRot(),PRIM_ROTATION, gRotArc * llGetRot()] );<br />
<br />
gives no derivation of the variables gPosOffset and gRotArc.<br />
Which is less than useful to someone learning from the text.<br />
[[User:Gregory McLeod|Gregory McLeod]] 08:51, 1 September 2008 (PDT)<br />
:missed this comment before. although it should be guessable that offset = gPosOffset, and rot6x = gRotArc, I went ahead and made the section more explicit, and converted it to use lsl highlighting (so that all keywords would be linked) and removed a few slightly misleading viewer frame references. <br/>-- '''[[User:Void_Singer|Void]]''' <sup><small>([[User_talk:Void_Singer|talk]]|[[Special:Contributions/Void_Singer|contribs]])</small></sup> 11:00, 19 May 2009 (UTC)<br />
<br />
== Useful snippets ==<br />
<br />
The snippet we have now is kind of a string function. [http://www.isner.com/tutorials/quatSpells/quaternion_spells_12.htm How about converting these] from XSI to LSL? <br />
<br />
[http://lslwiki.net/lslwiki/wakka.php?wakka=LibraryRotationFunctions How about these] from lslwiki.net? ("All functions on this page are released into public domain and may have been based off other public domain works.")<br />
<br />
By the way, someone above complained about an unlinked reference to slerp() which seems to now be completely missing(!) Both of those have slerp(). [[User:Gia May|Gia May]] 07:15, 8 December 2008 (UTC)<br />
<br />
:I offer L$5000 to the first person who translates two functions from http://www.isner.com/tutorials/quatSpells/quaternion_spells_12.htm to the Useful snippets here, or for code constraining rotations to an arbitrary conic section. Runners up, if any, will be awarded on merit, and I am also asking the Lindens to help with this library deficiency bug bounty. IM me inworld for details. [[User:JS Uralia|JS Uralia]] 21:17, 2 February 2009 (UTC)<br />
::Hello, I went ahead and added three such functions: ConstrainQuaternion2Plane, ScaleQuaternion and CombineQuaternions (Slerp) though this last one already existed on the Wiki.--[[User:Jesrad Seraph|Jesrad Seraph]] 07:05, 17 May 2009 (UTC)<br />
<br />
Pending fulfillment of my promise to pay Jesrad L$5000 -- and [http://wiki.secondlife.com/w/index.php?title=Rotation&diff=220643&oldid=167253 Mephistopheles Thalheimer can attest I keep my word on these bounty payments] -- could someone please independently verify that this function works as it should?<br />
<br />
<lsl>// Constrain a rotation to a given plane, defined by its normal, this is very useful for vehicles that remain horizontal in turns:<br />
rotation ConstrainQuat2Plane(rotation source, vector normal)<br />
{<br />
return llAxisAngle2Rot(normal, <source.x, source.y, source.z> * normal * llRot2Angle(source));<br />
} // Jesrad Seraph</lsl><br />
<br />
I'm very troubled by the use of the first three elements of the quaternion in that manner, but in all honestly, I don't know enough to figure out what a correct answer is. [[User:JS Uralia|JS Uralia]] 20:43, 23 May 2009 (UTC)<br />
<br />
:I think it might just be correct. I can't verify it at the moment but the math looks to have the correct properties though the magnitudes of the vectors going into the dot product worry me. I'm wondering if <source.x, source.y, source.z> shouldn't be normalized first. On a side note, it doesn't handle the edge cases where source and normal haven't been normalized. -- '''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 09:56, 24 May 2009 (UTC)<br />
::More testing shows it is off by sometimes as much as 90 degrees... I will try to correct it, probably by normalizing the vector part first like suggested.--[[User:Jesrad Seraph|Jesrad Seraph]] 14:52, 7 July 2009 (UTC)<br />
<br />
== With regard to rotations of a child of an attachment ==<br />
<br />
I blow a raspberry at lsl. -- '''[[User:EddyFragment Robonaught|Eddy]]''' <sup><small>([[User talk:EddyFragment_Robonaught|talk]]|[[Special:Contributions/EddyFragment_Robonaught|contribs]])</small></sup> 06:37, 13 July 2009 (UTC)<br />
<br />
:Don't you just love {{Jira|SVC-93}}? Gage me with a spoon *rolls eyes*. -- '''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 18:08, 13 July 2009 (UTC)<br />
<br />
Ah. Not just me then. I thought I just needed a degree in quantum maths to understand it. Thanx for the link. *voted* -- '''[[User:EddyFragment Robonaught|Eddy]]''' <sup><small>([[User talk:EddyFragment_Robonaught|talk]]|[[Special:Contributions/EddyFragment_Robonaught|contribs]])</small></sup> 01:41, 14 July 2009 (UTC)<br />
<br />
<br />
I think this is wrong: it claims that the llGetRot of a child prim of an attached object gives "global rotation of avatar * global rotation of prim (Not Useful)" This would be very useful if it were true and would let you calculate the rotation of the attach point. But I think llGetRot gives you the local rotation of the child prim * global rotation of the avatar, which is of no use that I can think of. I'm new at scripting so I'd appreciate some verification and so won't just change the page. [[User:Jonno Stromfield|Jonno Stromfield]] 11:04, 11 September 2009 (UTC)</div>Jonno Stromfieldhttps://wiki.secondlife.com/wiki/RotationRotation2009-10-21T12:10:26Z<p>Jonno Stromfield: /* Rotation */</p>
<hr />
<div>{{LSL Header|ml=*}}{{RightToc}}<br />
==Rotation==<br />
The LSL '''rotation''' type is one of several ways to represent an orientation in 3D. (Note that we try to write the type name in '''bold'''.)<br />
<br />
The '''rotation''' can be viewed as a discrete twist in three dimensional space, and the orientation of an object is how much it has been twisted round from whichever axes we are using - normally the region's axes.<br />
<br />
It is a mathematical object called a {{LSLG|quaternion}}. You can think of a quaternion as four numbers, three of which represent the direction an object is facing and a fourth that represents the object's banking left or right around that direction. The main advantage of using <br />
quaternions is that they are not susceptible to [http://en.wikipedia.org/wiki/Gimbal_Lock gimbal lock]. <br />
For the complex inner workings of quaternion mathematics, see {{LSLG|quaternion}}. <br />
For a list of functions and events related to rotations see {{LSLG|LSL Rotation Synopsis}}.<br />
There is also information about causing textures to rotate in {{LSLG|texture}}s.<br />
<br />
==Other representations==<br />
===Euler vector===<br />
Another way to represent a 3D angle is using three numbers, <X, Y, Z>, which represent the amount which the object is rotated around each axis. This is used in the Edit window, for example, and is generally easy for people to visualize. It is easy to adjust the Rotation <x, y, z> numbers in the Edit window and see how the object behaves. Note that in the Edit window, the numbers are in degrees, that is, a right angle is 90.<br />
<br />
In LSL, these three angles are expressed in [[radians]] instead of degrees, that is, a right angle is PI/2. (A radian is sort of a very fat degree.)<br />
Note that these three numbers are a '''vector''' type and not a '''rotation''' type, though it can represent the same information. This is called the ''Euler'' representation of a 3D angle. In LSL the rotation around z is done first, then around y, and finally around x.<br />
<br />
===Axis plus Turn Angle===<br />
In this method you define an axis of rotation, like defining the axis about which the earth spins, and use that together with the amount of turn about the axis to define the rotation.<br />
<br />
So if you want to define a rotation about an axis at 45 degrees in the x-y plane, that means you'd need the same amount of x and y, but no z. The axis could be <1.0, 1.0, 0.0>. The absolute size of the numbers defining the axis don’t matter in this representation; <2.0, 2.0, 0.0> would work just as well. The amount of turn angle is a separate number given in radians, eg. PI/3 = 60 degrees. <br />
<br />
Like a quaternion this uses four numbers, but you don’t have to worry about calculating sizes of the numbers you are using as much.<br />
<br />
===FWD, LEFT, UP=== <br />
Another way to represent the same 3D angle is to use three vectors, showing what the front is pointing at (fwd), what the top is pointing at (up), and what the left side is pointing at (left). Actually, only two of the three are needed, because any two determines the third. <br />
<br />
For good reasons, such as being able to easily combine rotations, the four number version, the '''rotation''', is better, though perhaps harder for a beginner to grasp. Fortunately it's very seldom necessary to do anything with the actual internal representation of ''rotations'' and there are functions for converting easily back and forth between the three LSL types, and between degrees and radians.<br />
<br />
==Right hand rule==<br />
In LSL all rotations are done according to the '''right hand rule'''. With your right hand, extend the first finger in the direction of the positive direction of the x-axis. Extend your second finger at right angles to your first finger, it will point along the positive y-axis, and your thumb, extended at right angles to both will point along the 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).<br />
<br />
http://en.wikipedia.org/wiki/Right_hand_rule<br />
<br />
Now, don't remove your right hand just yet, there is another use for it, determining the direction of a positive rotation. Make a fist with your right hand, thumb extended and pointing in the positive direction of the axis you are interested in. Your fingers curl around in the direction of positive rotation. Rotations around the X, Y, and Z axis are often referred to as Roll, Pitch, and Yaw, particularly for vehicles.<br />
<br />
[http://en.wikipedia.org/wiki/Tait-Bryan_angles Roll Pitch Yaw]<br />
<br />
== Combining Rotations ==<br />
'<br />
Suppose you have two rotations. ''r1'' is rotate 90 degrees to the left, and ''r2'' is rotate 30 degrees to the right. (Any rotations will work; these are just an example.)<br />
You can combine ''r1'' and ''r2'' to make ''r3'' using the '''*''' operator. It doesn't really multiply them, it ''composes'' them.<br />
<lsl><br />
rotation r3 = r1 * r2;<br />
</lsl><br />
The result in this case is that ''r3'' means rotate 60 degrees to the left.<br />
<br />
In other words, 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. The '''multiply''' operation applies the rotation in the positive direction, the '''divide''' operation does a negative rotation. You can also negate a rotation directly, just negate the s component, e.g. X.s = -X.s.<br />
<br />
Unlike other types such as {{LSLG|float}}, the order in which the operations are done, <br />
[http://en.wikipedia.org/wiki/Commutative non-commutative], is important.<br />
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.<br />
<br />
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.<br />
<br />
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.<br />
<br />
Clearly this is a different result from the first rotation, but the order of rotation is the only thing changed.<br />
<br />
To do a constant rotation you need to define a '''rotation''' value which can be done by creating a {{LSLG|vector}} with the X, Y, Z angles in radians as components (called an Euler angle), then converting that to a '''rotation''' by using the {{LSLG|llEuler2Rot}} function. To go from a rotation to an Euler angle {{LSLG|vector}} use {{LSLG|llRot2Euler}}.<br />
<br />
If you want an axial rotation you insert the axis of rotation and the turn angle into the {{LSLG|llAxisAngle2Rot}} function, and this will return the '''rotation'''. To go from a rotation back to axis and angle, use {{LSLG|llRot2Axis}} and {{LSLG|llRot2Angle}} respectively.<br />
<br />
You can alternately create the native rotation directly: the real part is the cosine of half the angle of rotation, and the vector part is the normalized axis of rotation multiplied by the sine of half the angle of rotation.<br />
<br />
'''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:<br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rot30X<br />
| style="white-space: nowrap" |= [[llEuler2Rot]](<30, 0, 0> * [[DEG_TO_RAD]]);<br />
||// convert the degrees to radians, then convert that [[vector]] into a rotation, rot30x<br />
|- valign="top"<br />
| style="white-space: nowrap" |[[vector]] vec30X <br />
| style="white-space: nowrap" |= [[llRot2Euler]](rot30X );<br />
||// convert the rotation back to a [[vector]] (the values will be in radians)<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rot30X<br />
| style="white-space: nowrap" |= [[llAxisAngle2Rot]](<1, 0, 0>, 30 * [[DEG_TO_RAD]]);<br />
||// convert the degrees to radians, then convert into a rotation, rot30x<br />
|}<br />
</div></div><br />
<br />
== Differences between math's quaternions and LSL rotations ==<br />
<br />
There are a few differences between LSL and maths that have little consequences while scripting, but that might puzzle people with prior mathematical knowledge. So we thought it would be good to list them here:<br />
<br />
* In LSL, all quaternions are normalized (the dot product of '''R''' by '''R''' is always '''1'''), and therefore represent ways to rotate objects without changing their size. In maths, generic quaternions might be not normalized, and they represent ''affinities'', i.e. a way to rotate '''and''' change the size of objects.<br />
* In LSL, the '''s''' term is the fourth member of the rotation: '''<x, y, z, s>'''. In maths, the '''s''' term, also called "real part", is written as the first coordinate of the quaternion: '''(s, x, y, z)'''.<br />
* Multiplication is written in reverse order in LSL and in maths. In LSL, you would write '''R * S''', where in maths you would write '''S . R'''.<br />
<br />
== Order of rotation for Euler Vectors ==<br />
<br />
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.<br />
<br />
== Local vs Global (World) rotations ==<br />
<br />
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.<br />
<br />
'''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.<br />
<br />
In LSL, the difference between doing a '''local''' or '''global''' rotation is the order the '''rotations''' are evaluated in the statement.<br />
<br />
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. <br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation localRot = <br />
| style="white-space: nowrap" |rot30X * myRot;<br />
||// do a local rotation by multiplying a constant rotation by a world rotation<br />
|}<br />
</div></div><br />
<br />
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.<br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation globalRot <br />
| style="white-space: nowrap" | = myRot * rot30X;<br />
||// do a global rotation by multiplying a world rotation by a constant rotation<br />
|}<br />
</div></div><br />
<br />
== Another way to think about combining rotations ==<br />
<br />
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.<br />
<br />
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.<br />
<br />
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.<br />
<br />
'''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'''.<br />
<br />
==Using Rotations ==<br />
<br />
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 [[float]]s, but there is overhead in unpacking them.<br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rot30X <br />
| style="white-space: nowrap" |= [[llEuler2Rot]](<30, 0, 0> * [[#DEG_TO_RAD|DEG_TO_RAD]] );<br />
||// Create a rotation constant<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rotCopy <br />
| style="white-space: nowrap" |= rot30X;<br />
||// Just copy it into rotCopy, it copies all 4 float components<br />
|- valign="top"<br />
| style="white-space: nowrap" |float X <br />
| style="white-space: nowrap" |= rotCopy.x;<br />
||// Get out the individual components of the rotation<br />
|- valign="top"<br />
| style="white-space: nowrap" |float Y <br />
| style="white-space: nowrap" |= rotCopy.y;<br />
||<br />
|- valign="top"<br />
| style="white-space: nowrap" |float Z <br />
| style="white-space: nowrap" |= rotCopy.z;<br />
||<br />
|- valign="top"<br />
| style="white-space: nowrap" |float S <br />
| style="white-space: nowrap" |= rotCopy.s;<br />
||<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation anotherCopy <br />
| style="white-space: nowrap" |= <X, Y, Z, S>;<br />
||// Make another rotation out of the components<br />
|}<br />
</div></div><br />
<br />
<br />
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.<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rot330X <br />
| style="white-space: nowrap" |= <-rot30X.x, -rot30X.y, -rot30X.z, rot30X.s>;<br />
||// invert a rotation - NOTE the s component isn't negated<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation another330X <br />
| style="white-space: nowrap" |= [[#ZERO_ROTATION|ZERO_ROTATION]] / rot30X;<br />
||// invert a rotation by division, same result as rot330X<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation yetanother330X <br />
| style="white-space: nowrap" |= <rot30X.x, rot30X.y, rot30X.z, -rot30X.s>;<br />
||// not literally the same but works the same.<br />
|}<br />
</div></div><br />
<br />
==Single or Root Prims vs Linked Prims vs Attachments ==<br />
<br />
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.<br />
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.<br />
<br />
{{LSLRotGetSet}}<br />
<br />
==Rotating Vectors ==<br />
<br />
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.<br />
<br />
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 [[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.<br />
=== Position of Object Rotated Around A Relative Point ===<br />
<lsl>rotation vRotArc = llEuler2Rot( <30.0, 0.0, 0.0> * DEG_TO_RAD );<br />
//-- creates a rotation constant, 30 degrees around the X axis<br />
<br />
vector vPosOffset = <0.0, 1.0, 0.0>;<br />
//-- creates an offset one meter in the positive Y direction<br />
<br />
vector vPosRotOffset = vPosOffset * vRotArc;<br />
//-- rotates the offset to get the motion caused by the rotation<br />
<br />
vector vPosOffsetDiff = vPosOffset - vPosRotOffset;<br />
//-- gets the local difference between the current offset and the rotated one<br />
<br />
vector vPosRotDiff = vPosOffsetDiff * llGetRot();<br />
//-- rotates the difference in the offsets to be relative to the global rotation.<br />
<br />
vector vPosNew = llGetPos() + vPosRotDiff;<br />
//-- finds the prims new position by adding the rotated offset difference<br />
<br />
rotation vRotNew = vRotArc * llGetRot();<br />
//-- finds rot to continue facing offset point</lsl><br />
:in application, the same action as:<br />
<lsl>llSetPrimitiveParams( [PRIM_POSITION, llGetPos() + (vPosOffset - vPosOffset * vRotArc) * llGetRot(),<br />
PRIM_ROTATION, vRotArc * llGetRot()] );</lsl><br />
* The above method results in the orbiting object always having the same side facing the center. An alternative that preserves the orbiters rotation is as follows<br />
<lsl>llSetPrimitiveParams( [PRIM_POSITION, llGetPos() + (vPosOffset - vPosOffset * vRotArc) * llGetRot()];<br />
vPosOffset = vPosOffset * vRotArc;</lsl><br />
'''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. Also to get a full orbit, you'll need to repeat the listed steps (in a [[timer]] perhaps).<br />
<br />
=== Position of Relative Point Around Rotated Object ===<br />
To get a point relative to the objects current facing (such as used in rezzors)<br />
<lsl>vector vPosOffset = <0.0, 0.0, 1.0>;<br />
//-- creates an offset one meter in the positive Z direction.<br />
<br />
vector vPosRotOffset = vPosOffset * llGetRot();<br />
//-- rotate the offset to be relative to objects rotation<br />
<br />
vector vPosOffsetIsAt = llGetPos() + vPosRotOffset;<br />
//-- get the region position of the rotated offset</lsl><br />
:in application, the same action as:<br />
<lsl>llRezAtRoot( "Object", llGetPos() + vPosOffset * llGetRot(), ZERO_VECTOR, llGetRot(), 0 );</lsl><br />
<br />
==Useful Snippets==<br />
<lsl>integer IsRotation(string s)<br />
{<br />
list split = llParseString2List(s, [" "], ["<", ">", ","]);<br />
if(llGetListLength(split) != 9)//we must check the list length, or the next test won't work properly.<br />
return 0;<br />
return !((string)((rotation)s) == (string)((rotation)((string)llListInsertList(split, ["-"], 7))));<br />
//it works by trying to flip the sign on the S element of the rotation,<br />
//if it works or breaks the rotation then the values won't match.<br />
//if the rotation was already broken then the sign flip will have no affect and the values will match<br />
//we cast back to string so we can catch negative zero which allows for support of <0,0,0,0><br />
}//Strife Onizuka</lsl><br />
<br />
<br />
// Calculate a point at distance d in the direction the avatar id is facing<br />
<lsl>vector point_in_front_of( key id, float d )<br />
{<br />
list pose = llGetObjectDetails( id, [ OBJECT_POS, OBJECT_ROT ] );<br />
return ( llList2Vector( pose, 0 ) + < d, 0.0, 0.0 > * llList2Rot( pose, 1 ) );<br />
}// Mephistopheles Thalheimer</lsl><br />
<br />
<br />
// Rez an object o at a distance d from the end of the z axis.<br />
// The object is rezzed oriented to the rezzer<br />
<br />
<lsl>rez_object_at_end( string o, float d )<br />
{<br />
vector s = llGetScale();<br />
<br />
if( llGetInventoryType( o ) == INVENTORY_OBJECT )<br />
{<br />
llRezObject( o, llGetPos() + llRot2Up( llGetRot() ) * ( s.z / 2.0 + d ) , ZERO_VECTOR, llGetRot(), 0 );<br />
}<br />
}// Mephistopheles Thalheimer</lsl><br />
<br />
// Useful functions converted to LSL from [http://www.isner.com/tutorials/quatSpells/quaternion_spells_12.htm this page]:<br />
<br />
// Scale a rotation:<br />
<lsl>rotation ScaleQuat(rotation source, float ratio)<br />
{<br />
return llAxisAngle2Rot(llRot2Axis(source), ratio * llRot2Angle(source));<br />
}</lsl><br />
<br />
// Constrain a rotation to a given plane, defined by its normal, this is very useful for vehicles that remain horizontal in turns:<br />
<lsl>rotation ConstrainQuat2Plane(rotation source, vector normal)<br />
{<br />
return llAxisAngle2Rot(normal, <source.x, source.y, source.z> * normal * llRot2Angle(source));<br />
} // Jesrad Seraph</lsl><br />
<br />
// Slerp (rotation combination) function from [[Slerp]]:<br />
<lsl>rotation BlendQuats(rotation a, rotation b, float ratio)<br />
{<br />
return llAxisAngle2Rot(llRot2Axis(b /= a), ratio * llRot2Angle(b)) * a;<br />
}</lsl><br />
<br />
== Constants ==<br />
=== [[ZERO_ROTATION]] ===<br />
ZERO_ROTATION = <0.0, 0.0, 0.0, 1.0>;<br/><br />
A rotation constant representing a Euler angle of <0.0, 0.0, 0.0>.<br />
<br />
=== [[DEG_TO_RAD]] ===<br />
DEG_TO_RAD = 0.01745329238f;<br/><br />
A float constant that when multiplied by an angle in degrees gives the angle in radians.<br />
<br />
=== [[RAD_TO_DEG]] ===<br />
RAD_TO_DEG = 57.29578f;<br/><br />
A float constant when multiplied by an angle in radians gives the angle in degrees.<br />
<br />
<br />
[[Category:LSL_Types|Rotation]][[Category:LSL_Math]][[Category:LSL_Math/3D]][[Category:LSL Rotation]]</div>Jonno Stromfieldhttps://wiki.secondlife.com/wiki/RotationRotation2009-10-21T12:02:01Z<p>Jonno Stromfield: /* Combining Rotations */</p>
<hr />
<div>{{LSL Header|ml=*}}{{RightToc}}<br />
==Rotation==<br />
The LSL '''rotation''' type is one of several ways to represent an orientation in 3D. (Note that we try to write the type name in '''bold'''.)<br />
It is a mathematical object called a {{LSLG|quaternion}}. You can think of a quaternion as four numbers, three of which represent the direction an object is facing and a fourth that represents the object's banking left or right around that direction. The main advantage of using <br />
quaternions is that they are not susceptible to [http://en.wikipedia.org/wiki/Gimbal_Lock gimbal lock]. <br />
For the complex inner workings of quaternion mathematics, see {{LSLG|quaternion}}. <br />
For a list of functions and events related to rotations see {{LSLG|LSL Rotation Synopsis}}.<br />
There is also information about causing textures to rotate in {{LSLG|texture}}s.<br />
<br />
==Other representations==<br />
===Euler vector===<br />
Another way to represent a 3D angle is using three numbers, <X, Y, Z>, which represent the amount which the object is rotated around each axis. This is used in the Edit window, for example, and is generally easy for people to visualize. It is easy to adjust the Rotation <x, y, z> numbers in the Edit window and see how the object behaves. Note that in the Edit window, the numbers are in degrees, that is, a right angle is 90.<br />
<br />
In LSL, these three angles are expressed in [[radians]] instead of degrees, that is, a right angle is PI/2. (A radian is sort of a very fat degree.)<br />
Note that these three numbers are a '''vector''' type and not a '''rotation''' type, though it can represent the same information. This is called the ''Euler'' representation of a 3D angle. In LSL the rotation around z is done first, then around y, and finally around x.<br />
<br />
===Axis plus Turn Angle===<br />
In this method you define an axis of rotation, like defining the axis about which the earth spins, and use that together with the amount of turn about the axis to define the rotation.<br />
<br />
So if you want to define a rotation about an axis at 45 degrees in the x-y plane, that means you'd need the same amount of x and y, but no z. The axis could be <1.0, 1.0, 0.0>. The absolute size of the numbers defining the axis don’t matter in this representation; <2.0, 2.0, 0.0> would work just as well. The amount of turn angle is a separate number given in radians, eg. PI/3 = 60 degrees. <br />
<br />
Like a quaternion this uses four numbers, but you don’t have to worry about calculating sizes of the numbers you are using as much.<br />
<br />
===FWD, LEFT, UP=== <br />
Another way to represent the same 3D angle is to use three vectors, showing what the front is pointing at (fwd), what the top is pointing at (up), and what the left side is pointing at (left). Actually, only two of the three are needed, because any two determines the third. <br />
<br />
For good reasons, such as being able to easily combine rotations, the four number version, the '''rotation''', is better, though perhaps harder for a beginner to grasp. Fortunately it's very seldom necessary to do anything with the actual internal representation of ''rotations'' and there are functions for converting easily back and forth between the three LSL types, and between degrees and radians.<br />
<br />
==Right hand rule==<br />
In LSL all rotations are done according to the '''right hand rule'''. With your right hand, extend the first finger in the direction of the positive direction of the x-axis. Extend your second finger at right angles to your first finger, it will point along the positive y-axis, and your thumb, extended at right angles to both will point along the 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).<br />
<br />
http://en.wikipedia.org/wiki/Right_hand_rule<br />
<br />
Now, don't remove your right hand just yet, there is another use for it, determining the direction of a positive rotation. Make a fist with your right hand, thumb extended and pointing in the positive direction of the axis you are interested in. Your fingers curl around in the direction of positive rotation. Rotations around the X, Y, and Z axis are often referred to as Roll, Pitch, and Yaw, particularly for vehicles.<br />
<br />
[http://en.wikipedia.org/wiki/Tait-Bryan_angles Roll Pitch Yaw]<br />
<br />
== Combining Rotations ==<br />
'<br />
Suppose you have two rotations. ''r1'' is rotate 90 degrees to the left, and ''r2'' is rotate 30 degrees to the right. (Any rotations will work; these are just an example.)<br />
You can combine ''r1'' and ''r2'' to make ''r3'' using the '''*''' operator. It doesn't really multiply them, it ''composes'' them.<br />
<lsl><br />
rotation r3 = r1 * r2;<br />
</lsl><br />
The result in this case is that ''r3'' means rotate 60 degrees to the left.<br />
<br />
In other words, 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. The '''multiply''' operation applies the rotation in the positive direction, the '''divide''' operation does a negative rotation. You can also negate a rotation directly, just negate the s component, e.g. X.s = -X.s.<br />
<br />
Unlike other types such as {{LSLG|float}}, the order in which the operations are done, <br />
[http://en.wikipedia.org/wiki/Commutative non-commutative], is important.<br />
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.<br />
<br />
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.<br />
<br />
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.<br />
<br />
Clearly this is a different result from the first rotation, but the order of rotation is the only thing changed.<br />
<br />
To do a constant rotation you need to define a '''rotation''' value which can be done by creating a {{LSLG|vector}} with the X, Y, Z angles in radians as components (called an Euler angle), then converting that to a '''rotation''' by using the {{LSLG|llEuler2Rot}} function. To go from a rotation to an Euler angle {{LSLG|vector}} use {{LSLG|llRot2Euler}}.<br />
<br />
If you want an axial rotation you insert the axis of rotation and the turn angle into the {{LSLG|llAxisAngle2Rot}} function, and this will return the '''rotation'''. To go from a rotation back to axis and angle, use {{LSLG|llRot2Axis}} and {{LSLG|llRot2Angle}} respectively.<br />
<br />
You can alternately create the native rotation directly: the real part is the cosine of half the angle of rotation, and the vector part is the normalized axis of rotation multiplied by the sine of half the angle of rotation.<br />
<br />
'''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:<br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rot30X<br />
| style="white-space: nowrap" |= [[llEuler2Rot]](<30, 0, 0> * [[DEG_TO_RAD]]);<br />
||// convert the degrees to radians, then convert that [[vector]] into a rotation, rot30x<br />
|- valign="top"<br />
| style="white-space: nowrap" |[[vector]] vec30X <br />
| style="white-space: nowrap" |= [[llRot2Euler]](rot30X );<br />
||// convert the rotation back to a [[vector]] (the values will be in radians)<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rot30X<br />
| style="white-space: nowrap" |= [[llAxisAngle2Rot]](<1, 0, 0>, 30 * [[DEG_TO_RAD]]);<br />
||// convert the degrees to radians, then convert into a rotation, rot30x<br />
|}<br />
</div></div><br />
<br />
== Differences between math's quaternions and LSL rotations ==<br />
<br />
There are a few differences between LSL and maths that have little consequences while scripting, but that might puzzle people with prior mathematical knowledge. So we thought it would be good to list them here:<br />
<br />
* In LSL, all quaternions are normalized (the dot product of '''R''' by '''R''' is always '''1'''), and therefore represent ways to rotate objects without changing their size. In maths, generic quaternions might be not normalized, and they represent ''affinities'', i.e. a way to rotate '''and''' change the size of objects.<br />
* In LSL, the '''s''' term is the fourth member of the rotation: '''<x, y, z, s>'''. In maths, the '''s''' term, also called "real part", is written as the first coordinate of the quaternion: '''(s, x, y, z)'''.<br />
* Multiplication is written in reverse order in LSL and in maths. In LSL, you would write '''R * S''', where in maths you would write '''S . R'''.<br />
<br />
== Order of rotation for Euler Vectors ==<br />
<br />
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.<br />
<br />
== Local vs Global (World) rotations ==<br />
<br />
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.<br />
<br />
'''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.<br />
<br />
In LSL, the difference between doing a '''local''' or '''global''' rotation is the order the '''rotations''' are evaluated in the statement.<br />
<br />
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. <br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation localRot = <br />
| style="white-space: nowrap" |rot30X * myRot;<br />
||// do a local rotation by multiplying a constant rotation by a world rotation<br />
|}<br />
</div></div><br />
<br />
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.<br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation globalRot <br />
| style="white-space: nowrap" | = myRot * rot30X;<br />
||// do a global rotation by multiplying a world rotation by a constant rotation<br />
|}<br />
</div></div><br />
<br />
== Another way to think about combining rotations ==<br />
<br />
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.<br />
<br />
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.<br />
<br />
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.<br />
<br />
'''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'''.<br />
<br />
==Using Rotations ==<br />
<br />
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 [[float]]s, but there is overhead in unpacking them.<br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rot30X <br />
| style="white-space: nowrap" |= [[llEuler2Rot]](<30, 0, 0> * [[#DEG_TO_RAD|DEG_TO_RAD]] );<br />
||// Create a rotation constant<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rotCopy <br />
| style="white-space: nowrap" |= rot30X;<br />
||// Just copy it into rotCopy, it copies all 4 float components<br />
|- valign="top"<br />
| style="white-space: nowrap" |float X <br />
| style="white-space: nowrap" |= rotCopy.x;<br />
||// Get out the individual components of the rotation<br />
|- valign="top"<br />
| style="white-space: nowrap" |float Y <br />
| style="white-space: nowrap" |= rotCopy.y;<br />
||<br />
|- valign="top"<br />
| style="white-space: nowrap" |float Z <br />
| style="white-space: nowrap" |= rotCopy.z;<br />
||<br />
|- valign="top"<br />
| style="white-space: nowrap" |float S <br />
| style="white-space: nowrap" |= rotCopy.s;<br />
||<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation anotherCopy <br />
| style="white-space: nowrap" |= <X, Y, Z, S>;<br />
||// Make another rotation out of the components<br />
|}<br />
</div></div><br />
<br />
<br />
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.<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rot330X <br />
| style="white-space: nowrap" |= <-rot30X.x, -rot30X.y, -rot30X.z, rot30X.s>;<br />
||// invert a rotation - NOTE the s component isn't negated<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation another330X <br />
| style="white-space: nowrap" |= [[#ZERO_ROTATION|ZERO_ROTATION]] / rot30X;<br />
||// invert a rotation by division, same result as rot330X<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation yetanother330X <br />
| style="white-space: nowrap" |= <rot30X.x, rot30X.y, rot30X.z, -rot30X.s>;<br />
||// not literally the same but works the same.<br />
|}<br />
</div></div><br />
<br />
==Single or Root Prims vs Linked Prims vs Attachments ==<br />
<br />
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.<br />
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.<br />
<br />
{{LSLRotGetSet}}<br />
<br />
==Rotating Vectors ==<br />
<br />
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.<br />
<br />
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 [[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.<br />
=== Position of Object Rotated Around A Relative Point ===<br />
<lsl>rotation vRotArc = llEuler2Rot( <30.0, 0.0, 0.0> * DEG_TO_RAD );<br />
//-- creates a rotation constant, 30 degrees around the X axis<br />
<br />
vector vPosOffset = <0.0, 1.0, 0.0>;<br />
//-- creates an offset one meter in the positive Y direction<br />
<br />
vector vPosRotOffset = vPosOffset * vRotArc;<br />
//-- rotates the offset to get the motion caused by the rotation<br />
<br />
vector vPosOffsetDiff = vPosOffset - vPosRotOffset;<br />
//-- gets the local difference between the current offset and the rotated one<br />
<br />
vector vPosRotDiff = vPosOffsetDiff * llGetRot();<br />
//-- rotates the difference in the offsets to be relative to the global rotation.<br />
<br />
vector vPosNew = llGetPos() + vPosRotDiff;<br />
//-- finds the prims new position by adding the rotated offset difference<br />
<br />
rotation vRotNew = vRotArc * llGetRot();<br />
//-- finds rot to continue facing offset point</lsl><br />
:in application, the same action as:<br />
<lsl>llSetPrimitiveParams( [PRIM_POSITION, llGetPos() + (vPosOffset - vPosOffset * vRotArc) * llGetRot(),<br />
PRIM_ROTATION, vRotArc * llGetRot()] );</lsl><br />
* The above method results in the orbiting object always having the same side facing the center. An alternative that preserves the orbiters rotation is as follows<br />
<lsl>llSetPrimitiveParams( [PRIM_POSITION, llGetPos() + (vPosOffset - vPosOffset * vRotArc) * llGetRot()];<br />
vPosOffset = vPosOffset * vRotArc;</lsl><br />
'''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. Also to get a full orbit, you'll need to repeat the listed steps (in a [[timer]] perhaps).<br />
<br />
=== Position of Relative Point Around Rotated Object ===<br />
To get a point relative to the objects current facing (such as used in rezzors)<br />
<lsl>vector vPosOffset = <0.0, 0.0, 1.0>;<br />
//-- creates an offset one meter in the positive Z direction.<br />
<br />
vector vPosRotOffset = vPosOffset * llGetRot();<br />
//-- rotate the offset to be relative to objects rotation<br />
<br />
vector vPosOffsetIsAt = llGetPos() + vPosRotOffset;<br />
//-- get the region position of the rotated offset</lsl><br />
:in application, the same action as:<br />
<lsl>llRezAtRoot( "Object", llGetPos() + vPosOffset * llGetRot(), ZERO_VECTOR, llGetRot(), 0 );</lsl><br />
<br />
==Useful Snippets==<br />
<lsl>integer IsRotation(string s)<br />
{<br />
list split = llParseString2List(s, [" "], ["<", ">", ","]);<br />
if(llGetListLength(split) != 9)//we must check the list length, or the next test won't work properly.<br />
return 0;<br />
return !((string)((rotation)s) == (string)((rotation)((string)llListInsertList(split, ["-"], 7))));<br />
//it works by trying to flip the sign on the S element of the rotation,<br />
//if it works or breaks the rotation then the values won't match.<br />
//if the rotation was already broken then the sign flip will have no affect and the values will match<br />
//we cast back to string so we can catch negative zero which allows for support of <0,0,0,0><br />
}//Strife Onizuka</lsl><br />
<br />
<br />
// Calculate a point at distance d in the direction the avatar id is facing<br />
<lsl>vector point_in_front_of( key id, float d )<br />
{<br />
list pose = llGetObjectDetails( id, [ OBJECT_POS, OBJECT_ROT ] );<br />
return ( llList2Vector( pose, 0 ) + < d, 0.0, 0.0 > * llList2Rot( pose, 1 ) );<br />
}// Mephistopheles Thalheimer</lsl><br />
<br />
<br />
// Rez an object o at a distance d from the end of the z axis.<br />
// The object is rezzed oriented to the rezzer<br />
<br />
<lsl>rez_object_at_end( string o, float d )<br />
{<br />
vector s = llGetScale();<br />
<br />
if( llGetInventoryType( o ) == INVENTORY_OBJECT )<br />
{<br />
llRezObject( o, llGetPos() + llRot2Up( llGetRot() ) * ( s.z / 2.0 + d ) , ZERO_VECTOR, llGetRot(), 0 );<br />
}<br />
}// Mephistopheles Thalheimer</lsl><br />
<br />
// Useful functions converted to LSL from [http://www.isner.com/tutorials/quatSpells/quaternion_spells_12.htm this page]:<br />
<br />
// Scale a rotation:<br />
<lsl>rotation ScaleQuat(rotation source, float ratio)<br />
{<br />
return llAxisAngle2Rot(llRot2Axis(source), ratio * llRot2Angle(source));<br />
}</lsl><br />
<br />
// Constrain a rotation to a given plane, defined by its normal, this is very useful for vehicles that remain horizontal in turns:<br />
<lsl>rotation ConstrainQuat2Plane(rotation source, vector normal)<br />
{<br />
return llAxisAngle2Rot(normal, <source.x, source.y, source.z> * normal * llRot2Angle(source));<br />
} // Jesrad Seraph</lsl><br />
<br />
// Slerp (rotation combination) function from [[Slerp]]:<br />
<lsl>rotation BlendQuats(rotation a, rotation b, float ratio)<br />
{<br />
return llAxisAngle2Rot(llRot2Axis(b /= a), ratio * llRot2Angle(b)) * a;<br />
}</lsl><br />
<br />
== Constants ==<br />
=== [[ZERO_ROTATION]] ===<br />
ZERO_ROTATION = <0.0, 0.0, 0.0, 1.0>;<br/><br />
A rotation constant representing a Euler angle of <0.0, 0.0, 0.0>.<br />
<br />
=== [[DEG_TO_RAD]] ===<br />
DEG_TO_RAD = 0.01745329238f;<br/><br />
A float constant that when multiplied by an angle in degrees gives the angle in radians.<br />
<br />
=== [[RAD_TO_DEG]] ===<br />
RAD_TO_DEG = 57.29578f;<br/><br />
A float constant when multiplied by an angle in radians gives the angle in degrees.<br />
<br />
<br />
[[Category:LSL_Types|Rotation]][[Category:LSL_Math]][[Category:LSL_Math/3D]][[Category:LSL Rotation]]</div>Jonno Stromfieldhttps://wiki.secondlife.com/wiki/RotationRotation2009-10-21T11:58:53Z<p>Jonno Stromfield: /* Combining Rotations */</p>
<hr />
<div>{{LSL Header|ml=*}}{{RightToc}}<br />
==Rotation==<br />
The LSL '''rotation''' type is one of several ways to represent an orientation in 3D. (Note that we try to write the type name in '''bold'''.)<br />
It is a mathematical object called a {{LSLG|quaternion}}. You can think of a quaternion as four numbers, three of which represent the direction an object is facing and a fourth that represents the object's banking left or right around that direction. The main advantage of using <br />
quaternions is that they are not susceptible to [http://en.wikipedia.org/wiki/Gimbal_Lock gimbal lock]. <br />
For the complex inner workings of quaternion mathematics, see {{LSLG|quaternion}}. <br />
For a list of functions and events related to rotations see {{LSLG|LSL Rotation Synopsis}}.<br />
There is also information about causing textures to rotate in {{LSLG|texture}}s.<br />
<br />
==Other representations==<br />
===Euler vector===<br />
Another way to represent a 3D angle is using three numbers, <X, Y, Z>, which represent the amount which the object is rotated around each axis. This is used in the Edit window, for example, and is generally easy for people to visualize. It is easy to adjust the Rotation <x, y, z> numbers in the Edit window and see how the object behaves. Note that in the Edit window, the numbers are in degrees, that is, a right angle is 90.<br />
<br />
In LSL, these three angles are expressed in [[radians]] instead of degrees, that is, a right angle is PI/2. (A radian is sort of a very fat degree.)<br />
Note that these three numbers are a '''vector''' type and not a '''rotation''' type, though it can represent the same information. This is called the ''Euler'' representation of a 3D angle. In LSL the rotation around z is done first, then around y, and finally around x.<br />
<br />
===Axis plus Turn Angle===<br />
In this method you define an axis of rotation, like defining the axis about which the earth spins, and use that together with the amount of turn about the axis to define the rotation.<br />
<br />
So if you want to define a rotation about an axis at 45 degrees in the x-y plane, that means you'd need the same amount of x and y, but no z. The axis could be <1.0, 1.0, 0.0>. The absolute size of the numbers defining the axis don’t matter in this representation; <2.0, 2.0, 0.0> would work just as well. The amount of turn angle is a separate number given in radians, eg. PI/3 = 60 degrees. <br />
<br />
Like a quaternion this uses four numbers, but you don’t have to worry about calculating sizes of the numbers you are using as much.<br />
<br />
===FWD, LEFT, UP=== <br />
Another way to represent the same 3D angle is to use three vectors, showing what the front is pointing at (fwd), what the top is pointing at (up), and what the left side is pointing at (left). Actually, only two of the three are needed, because any two determines the third. <br />
<br />
For good reasons, such as being able to easily combine rotations, the four number version, the '''rotation''', is better, though perhaps harder for a beginner to grasp. Fortunately it's very seldom necessary to do anything with the actual internal representation of ''rotations'' and there are functions for converting easily back and forth between the three LSL types, and between degrees and radians.<br />
<br />
==Right hand rule==<br />
In LSL all rotations are done according to the '''right hand rule'''. With your right hand, extend the first finger in the direction of the positive direction of the x-axis. Extend your second finger at right angles to your first finger, it will point along the positive y-axis, and your thumb, extended at right angles to both will point along the 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).<br />
<br />
http://en.wikipedia.org/wiki/Right_hand_rule<br />
<br />
Now, don't remove your right hand just yet, there is another use for it, determining the direction of a positive rotation. Make a fist with your right hand, thumb extended and pointing in the positive direction of the axis you are interested in. Your fingers curl around in the direction of positive rotation. Rotations around the X, Y, and Z axis are often referred to as Roll, Pitch, and Yaw, particularly for vehicles.<br />
<br />
[http://en.wikipedia.org/wiki/Tait-Bryan_angles Roll Pitch Yaw]<br />
<br />
== Combining Rotations ==<br />
'<br />
Suppose you have two rotations. ''r1'' is rotate 90 degrees to the left, and ''r2'' is rotate 30 degrees to the right. (Any rotations will work; these are just an example.)<br />
You can combine ''r1'' and ''r2'' to make ''r3'' using the '''*''' operator. It doesn't really multiply them, it ''composes'' them.<br />
<lsl><br />
rotation r3 = r1 * r2;<br />
</lsl><br />
The result in this case is that ''r3'' means rotate 60 degrees to the left.<br />
<br />
In other words, 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. The '''multiply''' operation applies the rotation in the positive direction, the '''divide''' operation does a negative rotation. You can also negate a rotation directly, just negate the s component, e.g. X.s = -X.s.<br />
<br />
Unlike other types such as {{LSLG|float}}, the order in which the operations are done, <br />
[http://en.wikipedia.org/wiki/Commutative non-commutative], is important.<br />
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.<br />
<br />
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.<br />
<br />
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.<br />
<br />
Clearly this is a different result from the first rotation, but the order of rotation is the only thing changed.<br />
<br />
To do a constant rotation you need to define a '''rotation''' value which can be done by creating a {{LSLG|vector}} with the X, Y, Z angles in radians as components (called an Euler angle), then converting that to a '''rotation''' by using the {{LSLG|llEuler2Rot}} function.<br />
<br />
If you want an axial rotation you insert the axis of rotation and the turn angle into the {{LSLG|llAxisAngle2Rot}} function, and this will return the '''rotation'''. To go from a rotation back to axis and angle, use {{LSLG|llRot2Axis}} and {{LSLG|llRot2Angle}} respectively.<br />
<br />
You can alternately create the native rotation directly: the real part is the cosine of half the angle of rotation, and the vector part is the normalized axis of rotation multiplied by the sine of half the angle of rotation. To go from a rotation to an Euler angle {{LSLG|vector}} use {{LSLG|llRot2Euler}}.<br />
<br />
'''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:<br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rot30X<br />
| style="white-space: nowrap" |= [[llEuler2Rot]](<30, 0, 0> * [[DEG_TO_RAD]]);<br />
||// convert the degrees to radians, then convert that [[vector]] into a rotation, rot30x<br />
|- valign="top"<br />
| style="white-space: nowrap" |[[vector]] vec30X <br />
| style="white-space: nowrap" |= [[llRot2Euler]](rot30X );<br />
||// convert the rotation back to a [[vector]] (the values will be in radians)<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rot30X<br />
| style="white-space: nowrap" |= [[llAxisAngle2Rot]](<1, 0, 0>, 30 * [[DEG_TO_RAD]]);<br />
||// convert the degrees to radians, then convert into a rotation, rot30x<br />
|}<br />
</div></div><br />
<br />
== Differences between math's quaternions and LSL rotations ==<br />
<br />
There are a few differences between LSL and maths that have little consequences while scripting, but that might puzzle people with prior mathematical knowledge. So we thought it would be good to list them here:<br />
<br />
* In LSL, all quaternions are normalized (the dot product of '''R''' by '''R''' is always '''1'''), and therefore represent ways to rotate objects without changing their size. In maths, generic quaternions might be not normalized, and they represent ''affinities'', i.e. a way to rotate '''and''' change the size of objects.<br />
* In LSL, the '''s''' term is the fourth member of the rotation: '''<x, y, z, s>'''. In maths, the '''s''' term, also called "real part", is written as the first coordinate of the quaternion: '''(s, x, y, z)'''.<br />
* Multiplication is written in reverse order in LSL and in maths. In LSL, you would write '''R * S''', where in maths you would write '''S . R'''.<br />
<br />
== Order of rotation for Euler Vectors ==<br />
<br />
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.<br />
<br />
== Local vs Global (World) rotations ==<br />
<br />
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.<br />
<br />
'''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.<br />
<br />
In LSL, the difference between doing a '''local''' or '''global''' rotation is the order the '''rotations''' are evaluated in the statement.<br />
<br />
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. <br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation localRot = <br />
| style="white-space: nowrap" |rot30X * myRot;<br />
||// do a local rotation by multiplying a constant rotation by a world rotation<br />
|}<br />
</div></div><br />
<br />
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.<br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation globalRot <br />
| style="white-space: nowrap" | = myRot * rot30X;<br />
||// do a global rotation by multiplying a world rotation by a constant rotation<br />
|}<br />
</div></div><br />
<br />
== Another way to think about combining rotations ==<br />
<br />
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.<br />
<br />
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.<br />
<br />
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.<br />
<br />
'''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'''.<br />
<br />
==Using Rotations ==<br />
<br />
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 [[float]]s, but there is overhead in unpacking them.<br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rot30X <br />
| style="white-space: nowrap" |= [[llEuler2Rot]](<30, 0, 0> * [[#DEG_TO_RAD|DEG_TO_RAD]] );<br />
||// Create a rotation constant<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rotCopy <br />
| style="white-space: nowrap" |= rot30X;<br />
||// Just copy it into rotCopy, it copies all 4 float components<br />
|- valign="top"<br />
| style="white-space: nowrap" |float X <br />
| style="white-space: nowrap" |= rotCopy.x;<br />
||// Get out the individual components of the rotation<br />
|- valign="top"<br />
| style="white-space: nowrap" |float Y <br />
| style="white-space: nowrap" |= rotCopy.y;<br />
||<br />
|- valign="top"<br />
| style="white-space: nowrap" |float Z <br />
| style="white-space: nowrap" |= rotCopy.z;<br />
||<br />
|- valign="top"<br />
| style="white-space: nowrap" |float S <br />
| style="white-space: nowrap" |= rotCopy.s;<br />
||<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation anotherCopy <br />
| style="white-space: nowrap" |= <X, Y, Z, S>;<br />
||// Make another rotation out of the components<br />
|}<br />
</div></div><br />
<br />
<br />
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.<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rot330X <br />
| style="white-space: nowrap" |= <-rot30X.x, -rot30X.y, -rot30X.z, rot30X.s>;<br />
||// invert a rotation - NOTE the s component isn't negated<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation another330X <br />
| style="white-space: nowrap" |= [[#ZERO_ROTATION|ZERO_ROTATION]] / rot30X;<br />
||// invert a rotation by division, same result as rot330X<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation yetanother330X <br />
| style="white-space: nowrap" |= <rot30X.x, rot30X.y, rot30X.z, -rot30X.s>;<br />
||// not literally the same but works the same.<br />
|}<br />
</div></div><br />
<br />
==Single or Root Prims vs Linked Prims vs Attachments ==<br />
<br />
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.<br />
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.<br />
<br />
{{LSLRotGetSet}}<br />
<br />
==Rotating Vectors ==<br />
<br />
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.<br />
<br />
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 [[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.<br />
=== Position of Object Rotated Around A Relative Point ===<br />
<lsl>rotation vRotArc = llEuler2Rot( <30.0, 0.0, 0.0> * DEG_TO_RAD );<br />
//-- creates a rotation constant, 30 degrees around the X axis<br />
<br />
vector vPosOffset = <0.0, 1.0, 0.0>;<br />
//-- creates an offset one meter in the positive Y direction<br />
<br />
vector vPosRotOffset = vPosOffset * vRotArc;<br />
//-- rotates the offset to get the motion caused by the rotation<br />
<br />
vector vPosOffsetDiff = vPosOffset - vPosRotOffset;<br />
//-- gets the local difference between the current offset and the rotated one<br />
<br />
vector vPosRotDiff = vPosOffsetDiff * llGetRot();<br />
//-- rotates the difference in the offsets to be relative to the global rotation.<br />
<br />
vector vPosNew = llGetPos() + vPosRotDiff;<br />
//-- finds the prims new position by adding the rotated offset difference<br />
<br />
rotation vRotNew = vRotArc * llGetRot();<br />
//-- finds rot to continue facing offset point</lsl><br />
:in application, the same action as:<br />
<lsl>llSetPrimitiveParams( [PRIM_POSITION, llGetPos() + (vPosOffset - vPosOffset * vRotArc) * llGetRot(),<br />
PRIM_ROTATION, vRotArc * llGetRot()] );</lsl><br />
* The above method results in the orbiting object always having the same side facing the center. An alternative that preserves the orbiters rotation is as follows<br />
<lsl>llSetPrimitiveParams( [PRIM_POSITION, llGetPos() + (vPosOffset - vPosOffset * vRotArc) * llGetRot()];<br />
vPosOffset = vPosOffset * vRotArc;</lsl><br />
'''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. Also to get a full orbit, you'll need to repeat the listed steps (in a [[timer]] perhaps).<br />
<br />
=== Position of Relative Point Around Rotated Object ===<br />
To get a point relative to the objects current facing (such as used in rezzors)<br />
<lsl>vector vPosOffset = <0.0, 0.0, 1.0>;<br />
//-- creates an offset one meter in the positive Z direction.<br />
<br />
vector vPosRotOffset = vPosOffset * llGetRot();<br />
//-- rotate the offset to be relative to objects rotation<br />
<br />
vector vPosOffsetIsAt = llGetPos() + vPosRotOffset;<br />
//-- get the region position of the rotated offset</lsl><br />
:in application, the same action as:<br />
<lsl>llRezAtRoot( "Object", llGetPos() + vPosOffset * llGetRot(), ZERO_VECTOR, llGetRot(), 0 );</lsl><br />
<br />
==Useful Snippets==<br />
<lsl>integer IsRotation(string s)<br />
{<br />
list split = llParseString2List(s, [" "], ["<", ">", ","]);<br />
if(llGetListLength(split) != 9)//we must check the list length, or the next test won't work properly.<br />
return 0;<br />
return !((string)((rotation)s) == (string)((rotation)((string)llListInsertList(split, ["-"], 7))));<br />
//it works by trying to flip the sign on the S element of the rotation,<br />
//if it works or breaks the rotation then the values won't match.<br />
//if the rotation was already broken then the sign flip will have no affect and the values will match<br />
//we cast back to string so we can catch negative zero which allows for support of <0,0,0,0><br />
}//Strife Onizuka</lsl><br />
<br />
<br />
// Calculate a point at distance d in the direction the avatar id is facing<br />
<lsl>vector point_in_front_of( key id, float d )<br />
{<br />
list pose = llGetObjectDetails( id, [ OBJECT_POS, OBJECT_ROT ] );<br />
return ( llList2Vector( pose, 0 ) + < d, 0.0, 0.0 > * llList2Rot( pose, 1 ) );<br />
}// Mephistopheles Thalheimer</lsl><br />
<br />
<br />
// Rez an object o at a distance d from the end of the z axis.<br />
// The object is rezzed oriented to the rezzer<br />
<br />
<lsl>rez_object_at_end( string o, float d )<br />
{<br />
vector s = llGetScale();<br />
<br />
if( llGetInventoryType( o ) == INVENTORY_OBJECT )<br />
{<br />
llRezObject( o, llGetPos() + llRot2Up( llGetRot() ) * ( s.z / 2.0 + d ) , ZERO_VECTOR, llGetRot(), 0 );<br />
}<br />
}// Mephistopheles Thalheimer</lsl><br />
<br />
// Useful functions converted to LSL from [http://www.isner.com/tutorials/quatSpells/quaternion_spells_12.htm this page]:<br />
<br />
// Scale a rotation:<br />
<lsl>rotation ScaleQuat(rotation source, float ratio)<br />
{<br />
return llAxisAngle2Rot(llRot2Axis(source), ratio * llRot2Angle(source));<br />
}</lsl><br />
<br />
// Constrain a rotation to a given plane, defined by its normal, this is very useful for vehicles that remain horizontal in turns:<br />
<lsl>rotation ConstrainQuat2Plane(rotation source, vector normal)<br />
{<br />
return llAxisAngle2Rot(normal, <source.x, source.y, source.z> * normal * llRot2Angle(source));<br />
} // Jesrad Seraph</lsl><br />
<br />
// Slerp (rotation combination) function from [[Slerp]]:<br />
<lsl>rotation BlendQuats(rotation a, rotation b, float ratio)<br />
{<br />
return llAxisAngle2Rot(llRot2Axis(b /= a), ratio * llRot2Angle(b)) * a;<br />
}</lsl><br />
<br />
== Constants ==<br />
=== [[ZERO_ROTATION]] ===<br />
ZERO_ROTATION = <0.0, 0.0, 0.0, 1.0>;<br/><br />
A rotation constant representing a Euler angle of <0.0, 0.0, 0.0>.<br />
<br />
=== [[DEG_TO_RAD]] ===<br />
DEG_TO_RAD = 0.01745329238f;<br/><br />
A float constant that when multiplied by an angle in degrees gives the angle in radians.<br />
<br />
=== [[RAD_TO_DEG]] ===<br />
RAD_TO_DEG = 57.29578f;<br/><br />
A float constant when multiplied by an angle in radians gives the angle in degrees.<br />
<br />
<br />
[[Category:LSL_Types|Rotation]][[Category:LSL_Math]][[Category:LSL_Math/3D]][[Category:LSL Rotation]]</div>Jonno Stromfieldhttps://wiki.secondlife.com/wiki/RotationRotation2009-10-21T11:43:01Z<p>Jonno Stromfield: /* Other representations */</p>
<hr />
<div>{{LSL Header|ml=*}}{{RightToc}}<br />
==Rotation==<br />
The LSL '''rotation''' type is one of several ways to represent an orientation in 3D. (Note that we try to write the type name in '''bold'''.)<br />
It is a mathematical object called a {{LSLG|quaternion}}. You can think of a quaternion as four numbers, three of which represent the direction an object is facing and a fourth that represents the object's banking left or right around that direction. The main advantage of using <br />
quaternions is that they are not susceptible to [http://en.wikipedia.org/wiki/Gimbal_Lock gimbal lock]. <br />
For the complex inner workings of quaternion mathematics, see {{LSLG|quaternion}}. <br />
For a list of functions and events related to rotations see {{LSLG|LSL Rotation Synopsis}}.<br />
There is also information about causing textures to rotate in {{LSLG|texture}}s.<br />
<br />
==Other representations==<br />
===Euler vector===<br />
Another way to represent a 3D angle is using three numbers, <X, Y, Z>, which represent the amount which the object is rotated around each axis. This is used in the Edit window, for example, and is generally easy for people to visualize. It is easy to adjust the Rotation <x, y, z> numbers in the Edit window and see how the object behaves. Note that in the Edit window, the numbers are in degrees, that is, a right angle is 90.<br />
<br />
In LSL, these three angles are expressed in [[radians]] instead of degrees, that is, a right angle is PI/2. (A radian is sort of a very fat degree.)<br />
Note that these three numbers are a '''vector''' type and not a '''rotation''' type, though it can represent the same information. This is called the ''Euler'' representation of a 3D angle. In LSL the rotation around z is done first, then around y, and finally around x.<br />
<br />
===Axis plus Turn Angle===<br />
In this method you define an axis of rotation, like defining the axis about which the earth spins, and use that together with the amount of turn about the axis to define the rotation.<br />
<br />
So if you want to define a rotation about an axis at 45 degrees in the x-y plane, that means you'd need the same amount of x and y, but no z. The axis could be <1.0, 1.0, 0.0>. The absolute size of the numbers defining the axis don’t matter in this representation; <2.0, 2.0, 0.0> would work just as well. The amount of turn angle is a separate number given in radians, eg. PI/3 = 60 degrees. <br />
<br />
Like a quaternion this uses four numbers, but you don’t have to worry about calculating sizes of the numbers you are using as much.<br />
<br />
===FWD, LEFT, UP=== <br />
Another way to represent the same 3D angle is to use three vectors, showing what the front is pointing at (fwd), what the top is pointing at (up), and what the left side is pointing at (left). Actually, only two of the three are needed, because any two determines the third. <br />
<br />
For good reasons, such as being able to easily combine rotations, the four number version, the '''rotation''', is better, though perhaps harder for a beginner to grasp. Fortunately it's very seldom necessary to do anything with the actual internal representation of ''rotations'' and there are functions for converting easily back and forth between the three LSL types, and between degrees and radians.<br />
<br />
==Right hand rule==<br />
In LSL all rotations are done according to the '''right hand rule'''. With your right hand, extend the first finger in the direction of the positive direction of the x-axis. Extend your second finger at right angles to your first finger, it will point along the positive y-axis, and your thumb, extended at right angles to both will point along the 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).<br />
<br />
http://en.wikipedia.org/wiki/Right_hand_rule<br />
<br />
Now, don't remove your right hand just yet, there is another use for it, determining the direction of a positive rotation. Make a fist with your right hand, thumb extended and pointing in the positive direction of the axis you are interested in. Your fingers curl around in the direction of positive rotation. Rotations around the X, Y, and Z axis are often referred to as Roll, Pitch, and Yaw, particularly for vehicles.<br />
<br />
[http://en.wikipedia.org/wiki/Tait-Bryan_angles Roll Pitch Yaw]<br />
<br />
== Combining Rotations ==<br />
'<br />
Suppose you have two rotations. ''r1'' is rotate 90 degrees to the left, and ''r2'' is rotate 30 degrees to the right. (Any rotations will work; these are just an example.)<br />
You can combine ''r1'' and ''r2'' to make ''r3'' using the '''*''' operator. It doesn't really multiply them, it ''composes'' them.<br />
<lsl><br />
rotation r3 = r1 * r2;<br />
</lsl><br />
The result in this case is that ''r3'' means rotate 60 degrees to the left.<br />
<br />
In other words, 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. The '''multiply''' operation applies the rotation in the positive direction, the '''divide''' operation does a negative rotation. You can also negate a rotation directly, just negate the s component, e.g. X.s = -X.s.<br />
<br />
Unlike other types such as {{LSLG|float}}, the order in which the operations are done, <br />
[http://en.wikipedia.org/wiki/Commutative non-commutative], is important.<br />
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.<br />
<br />
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.<br />
<br />
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.<br />
<br />
Clearly this is a different result from the first rotation, but the order of rotation is the only thing changed.<br />
<br />
To do a constant rotation you need to define a '''rotation''' value which can be done by creating a {{LSLG|vector}} with the X, Y, Z angles in radians as components (called an Euler angle), then converting that to a '''rotation''' by using the {{LSLG|llEuler2Rot}} function. You can alternately create the native rotation directly: the real part is the cosine of half the angle of rotation, and the vector part is the normalized axis of rotation multiplied by the sine of half the angle of rotation. To go from a rotation to an Euler angle {{LSLG|vector}} use {{LSLG|llRot2Euler}}.<br />
<br />
'''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:<br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rot30X<br />
| style="white-space: nowrap" |= [[llEuler2Rot]](<30, 0, 0> * [[DEG_TO_RAD]]);<br />
||// convert the degrees to radians, then convert that [[vector]] into a rotation, rot30x<br />
|- valign="top"<br />
| style="white-space: nowrap" |[[vector]] vec30X <br />
| style="white-space: nowrap" |= [[llRot2Euler]](rot30X );<br />
||// convert the rotation back to a [[vector]] (the values will be in radians)<br />
|}<br />
</div></div><br />
<br />
== Differences between math's quaternions and LSL rotations ==<br />
<br />
There are a few differences between LSL and maths that have little consequences while scripting, but that might puzzle people with prior mathematical knowledge. So we thought it would be good to list them here:<br />
<br />
* In LSL, all quaternions are normalized (the dot product of '''R''' by '''R''' is always '''1'''), and therefore represent ways to rotate objects without changing their size. In maths, generic quaternions might be not normalized, and they represent ''affinities'', i.e. a way to rotate '''and''' change the size of objects.<br />
* In LSL, the '''s''' term is the fourth member of the rotation: '''<x, y, z, s>'''. In maths, the '''s''' term, also called "real part", is written as the first coordinate of the quaternion: '''(s, x, y, z)'''.<br />
* Multiplication is written in reverse order in LSL and in maths. In LSL, you would write '''R * S''', where in maths you would write '''S . R'''.<br />
<br />
== Order of rotation for Euler Vectors ==<br />
<br />
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.<br />
<br />
== Local vs Global (World) rotations ==<br />
<br />
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.<br />
<br />
'''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.<br />
<br />
In LSL, the difference between doing a '''local''' or '''global''' rotation is the order the '''rotations''' are evaluated in the statement.<br />
<br />
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. <br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation localRot = <br />
| style="white-space: nowrap" |rot30X * myRot;<br />
||// do a local rotation by multiplying a constant rotation by a world rotation<br />
|}<br />
</div></div><br />
<br />
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.<br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation globalRot <br />
| style="white-space: nowrap" | = myRot * rot30X;<br />
||// do a global rotation by multiplying a world rotation by a constant rotation<br />
|}<br />
</div></div><br />
<br />
== Another way to think about combining rotations ==<br />
<br />
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.<br />
<br />
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.<br />
<br />
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.<br />
<br />
'''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'''.<br />
<br />
==Using Rotations ==<br />
<br />
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 [[float]]s, but there is overhead in unpacking them.<br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rot30X <br />
| style="white-space: nowrap" |= [[llEuler2Rot]](<30, 0, 0> * [[#DEG_TO_RAD|DEG_TO_RAD]] );<br />
||// Create a rotation constant<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rotCopy <br />
| style="white-space: nowrap" |= rot30X;<br />
||// Just copy it into rotCopy, it copies all 4 float components<br />
|- valign="top"<br />
| style="white-space: nowrap" |float X <br />
| style="white-space: nowrap" |= rotCopy.x;<br />
||// Get out the individual components of the rotation<br />
|- valign="top"<br />
| style="white-space: nowrap" |float Y <br />
| style="white-space: nowrap" |= rotCopy.y;<br />
||<br />
|- valign="top"<br />
| style="white-space: nowrap" |float Z <br />
| style="white-space: nowrap" |= rotCopy.z;<br />
||<br />
|- valign="top"<br />
| style="white-space: nowrap" |float S <br />
| style="white-space: nowrap" |= rotCopy.s;<br />
||<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation anotherCopy <br />
| style="white-space: nowrap" |= <X, Y, Z, S>;<br />
||// Make another rotation out of the components<br />
|}<br />
</div></div><br />
<br />
<br />
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.<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rot330X <br />
| style="white-space: nowrap" |= <-rot30X.x, -rot30X.y, -rot30X.z, rot30X.s>;<br />
||// invert a rotation - NOTE the s component isn't negated<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation another330X <br />
| style="white-space: nowrap" |= [[#ZERO_ROTATION|ZERO_ROTATION]] / rot30X;<br />
||// invert a rotation by division, same result as rot330X<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation yetanother330X <br />
| style="white-space: nowrap" |= <rot30X.x, rot30X.y, rot30X.z, -rot30X.s>;<br />
||// not literally the same but works the same.<br />
|}<br />
</div></div><br />
<br />
==Single or Root Prims vs Linked Prims vs Attachments ==<br />
<br />
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.<br />
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.<br />
<br />
{{LSLRotGetSet}}<br />
<br />
==Rotating Vectors ==<br />
<br />
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.<br />
<br />
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 [[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.<br />
=== Position of Object Rotated Around A Relative Point ===<br />
<lsl>rotation vRotArc = llEuler2Rot( <30.0, 0.0, 0.0> * DEG_TO_RAD );<br />
//-- creates a rotation constant, 30 degrees around the X axis<br />
<br />
vector vPosOffset = <0.0, 1.0, 0.0>;<br />
//-- creates an offset one meter in the positive Y direction<br />
<br />
vector vPosRotOffset = vPosOffset * vRotArc;<br />
//-- rotates the offset to get the motion caused by the rotation<br />
<br />
vector vPosOffsetDiff = vPosOffset - vPosRotOffset;<br />
//-- gets the local difference between the current offset and the rotated one<br />
<br />
vector vPosRotDiff = vPosOffsetDiff * llGetRot();<br />
//-- rotates the difference in the offsets to be relative to the global rotation.<br />
<br />
vector vPosNew = llGetPos() + vPosRotDiff;<br />
//-- finds the prims new position by adding the rotated offset difference<br />
<br />
rotation vRotNew = vRotArc * llGetRot();<br />
//-- finds rot to continue facing offset point</lsl><br />
:in application, the same action as:<br />
<lsl>llSetPrimitiveParams( [PRIM_POSITION, llGetPos() + (vPosOffset - vPosOffset * vRotArc) * llGetRot(),<br />
PRIM_ROTATION, vRotArc * llGetRot()] );</lsl><br />
* The above method results in the orbiting object always having the same side facing the center. An alternative that preserves the orbiters rotation is as follows<br />
<lsl>llSetPrimitiveParams( [PRIM_POSITION, llGetPos() + (vPosOffset - vPosOffset * vRotArc) * llGetRot()];<br />
vPosOffset = vPosOffset * vRotArc;</lsl><br />
'''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. Also to get a full orbit, you'll need to repeat the listed steps (in a [[timer]] perhaps).<br />
<br />
=== Position of Relative Point Around Rotated Object ===<br />
To get a point relative to the objects current facing (such as used in rezzors)<br />
<lsl>vector vPosOffset = <0.0, 0.0, 1.0>;<br />
//-- creates an offset one meter in the positive Z direction.<br />
<br />
vector vPosRotOffset = vPosOffset * llGetRot();<br />
//-- rotate the offset to be relative to objects rotation<br />
<br />
vector vPosOffsetIsAt = llGetPos() + vPosRotOffset;<br />
//-- get the region position of the rotated offset</lsl><br />
:in application, the same action as:<br />
<lsl>llRezAtRoot( "Object", llGetPos() + vPosOffset * llGetRot(), ZERO_VECTOR, llGetRot(), 0 );</lsl><br />
<br />
==Useful Snippets==<br />
<lsl>integer IsRotation(string s)<br />
{<br />
list split = llParseString2List(s, [" "], ["<", ">", ","]);<br />
if(llGetListLength(split) != 9)//we must check the list length, or the next test won't work properly.<br />
return 0;<br />
return !((string)((rotation)s) == (string)((rotation)((string)llListInsertList(split, ["-"], 7))));<br />
//it works by trying to flip the sign on the S element of the rotation,<br />
//if it works or breaks the rotation then the values won't match.<br />
//if the rotation was already broken then the sign flip will have no affect and the values will match<br />
//we cast back to string so we can catch negative zero which allows for support of <0,0,0,0><br />
}//Strife Onizuka</lsl><br />
<br />
<br />
// Calculate a point at distance d in the direction the avatar id is facing<br />
<lsl>vector point_in_front_of( key id, float d )<br />
{<br />
list pose = llGetObjectDetails( id, [ OBJECT_POS, OBJECT_ROT ] );<br />
return ( llList2Vector( pose, 0 ) + < d, 0.0, 0.0 > * llList2Rot( pose, 1 ) );<br />
}// Mephistopheles Thalheimer</lsl><br />
<br />
<br />
// Rez an object o at a distance d from the end of the z axis.<br />
// The object is rezzed oriented to the rezzer<br />
<br />
<lsl>rez_object_at_end( string o, float d )<br />
{<br />
vector s = llGetScale();<br />
<br />
if( llGetInventoryType( o ) == INVENTORY_OBJECT )<br />
{<br />
llRezObject( o, llGetPos() + llRot2Up( llGetRot() ) * ( s.z / 2.0 + d ) , ZERO_VECTOR, llGetRot(), 0 );<br />
}<br />
}// Mephistopheles Thalheimer</lsl><br />
<br />
// Useful functions converted to LSL from [http://www.isner.com/tutorials/quatSpells/quaternion_spells_12.htm this page]:<br />
<br />
// Scale a rotation:<br />
<lsl>rotation ScaleQuat(rotation source, float ratio)<br />
{<br />
return llAxisAngle2Rot(llRot2Axis(source), ratio * llRot2Angle(source));<br />
}</lsl><br />
<br />
// Constrain a rotation to a given plane, defined by its normal, this is very useful for vehicles that remain horizontal in turns:<br />
<lsl>rotation ConstrainQuat2Plane(rotation source, vector normal)<br />
{<br />
return llAxisAngle2Rot(normal, <source.x, source.y, source.z> * normal * llRot2Angle(source));<br />
} // Jesrad Seraph</lsl><br />
<br />
// Slerp (rotation combination) function from [[Slerp]]:<br />
<lsl>rotation BlendQuats(rotation a, rotation b, float ratio)<br />
{<br />
return llAxisAngle2Rot(llRot2Axis(b /= a), ratio * llRot2Angle(b)) * a;<br />
}</lsl><br />
<br />
== Constants ==<br />
=== [[ZERO_ROTATION]] ===<br />
ZERO_ROTATION = <0.0, 0.0, 0.0, 1.0>;<br/><br />
A rotation constant representing a Euler angle of <0.0, 0.0, 0.0>.<br />
<br />
=== [[DEG_TO_RAD]] ===<br />
DEG_TO_RAD = 0.01745329238f;<br/><br />
A float constant that when multiplied by an angle in degrees gives the angle in radians.<br />
<br />
=== [[RAD_TO_DEG]] ===<br />
RAD_TO_DEG = 57.29578f;<br/><br />
A float constant when multiplied by an angle in radians gives the angle in degrees.<br />
<br />
<br />
[[Category:LSL_Types|Rotation]][[Category:LSL_Math]][[Category:LSL_Math/3D]][[Category:LSL Rotation]]</div>Jonno Stromfieldhttps://wiki.secondlife.com/wiki/RotationRotation2009-10-21T10:14:39Z<p>Jonno Stromfield: /* Euler vector */</p>
<hr />
<div>{{LSL Header|ml=*}}{{RightToc}}<br />
==Rotation==<br />
The LSL '''rotation''' type is one of several ways to represent an orientation in 3D. (Note that we try to write the type name in '''bold'''.)<br />
It is a mathematical object called a {{LSLG|quaternion}}. You can think of a quaternion as four numbers, three of which represent the direction an object is facing and a fourth that represents the object's banking left or right around that direction. The main advantage of using <br />
quaternions is that they are not susceptible to [http://en.wikipedia.org/wiki/Gimbal_Lock gimbal lock]. <br />
For the complex inner workings of quaternion mathematics, see {{LSLG|quaternion}}. <br />
For a list of functions and events related to rotations see {{LSLG|LSL Rotation Synopsis}}.<br />
There is also information about causing textures to rotate in {{LSLG|texture}}s.<br />
<br />
==Other representations==<br />
===Euler vector===<br />
Another way to represent a 3D angle is using three numbers, <X, Y, Z>, which represent the amount which the object is rotated around each axis. This is used in the Edit window, for example, and is generally easy for people to visualize. It is easy to adjust the Rotation <x, y, z> numbers in the Edit window and see how the object behaves. Note that in the Edit window, the numbers are in degrees, that is, a right angle is 90.<br />
<br />
In LSL, these three angles are expressed in [[radians]] instead of degrees, that is, a right angle is PI/2. (A radian is sort of a very fat degree.)<br />
Note that these three numbers are a '''vector''' type and not a '''rotation''' type, though it can represent the same information. This is called the ''Euler'' representation of a 3D angle. In LSL the rotation around z is done first, then around y, and finally around x.<br />
<br />
===FWD, LEFT, UP=== <br />
Another way to represent the same 3D angle is to use three vectors, showing what the front is pointing at (fwd), what the top is pointing at (up), and what the left side is pointing at (left). Actually, only two of the three are needed, because any two determines the third. <br />
<br />
For good reasons, such as being able to easily combine rotations, the four number version, the '''rotation''', is better, though perhaps harder for a beginner to grasp. Fortunately it's very seldom necessary to do anything with the actual internal representation of ''rotations'' and there are functions for converting easily back and forth between the three LSL types, and between degrees and radians.<br />
<br />
==Right hand rule==<br />
In LSL all rotations are done according to the '''right hand rule'''. With your right hand, extend the first finger in the direction of the positive direction of the x-axis. Extend your second finger at right angles to your first finger, it will point along the positive y-axis, and your thumb, extended at right angles to both will point along the 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).<br />
<br />
http://en.wikipedia.org/wiki/Right_hand_rule<br />
<br />
Now, don't remove your right hand just yet, there is another use for it, determining the direction of a positive rotation. Make a fist with your right hand, thumb extended and pointing in the positive direction of the axis you are interested in. Your fingers curl around in the direction of positive rotation. Rotations around the X, Y, and Z axis are often referred to as Roll, Pitch, and Yaw, particularly for vehicles.<br />
<br />
[http://en.wikipedia.org/wiki/Tait-Bryan_angles Roll Pitch Yaw]<br />
<br />
== Combining Rotations ==<br />
'<br />
Suppose you have two rotations. ''r1'' is rotate 90 degrees to the left, and ''r2'' is rotate 30 degrees to the right. (Any rotations will work; these are just an example.)<br />
You can combine ''r1'' and ''r2'' to make ''r3'' using the '''*''' operator. It doesn't really multiply them, it ''composes'' them.<br />
<lsl><br />
rotation r3 = r1 * r2;<br />
</lsl><br />
The result in this case is that ''r3'' means rotate 60 degrees to the left.<br />
<br />
In other words, 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. The '''multiply''' operation applies the rotation in the positive direction, the '''divide''' operation does a negative rotation. You can also negate a rotation directly, just negate the s component, e.g. X.s = -X.s.<br />
<br />
Unlike other types such as {{LSLG|float}}, the order in which the operations are done, <br />
[http://en.wikipedia.org/wiki/Commutative non-commutative], is important.<br />
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.<br />
<br />
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.<br />
<br />
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.<br />
<br />
Clearly this is a different result from the first rotation, but the order of rotation is the only thing changed.<br />
<br />
To do a constant rotation you need to define a '''rotation''' value which can be done by creating a {{LSLG|vector}} with the X, Y, Z angles in radians as components (called an Euler angle), then converting that to a '''rotation''' by using the {{LSLG|llEuler2Rot}} function. You can alternately create the native rotation directly: the real part is the cosine of half the angle of rotation, and the vector part is the normalized axis of rotation multiplied by the sine of half the angle of rotation. To go from a rotation to an Euler angle {{LSLG|vector}} use {{LSLG|llRot2Euler}}.<br />
<br />
'''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:<br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rot30X<br />
| style="white-space: nowrap" |= [[llEuler2Rot]](<30, 0, 0> * [[DEG_TO_RAD]]);<br />
||// convert the degrees to radians, then convert that [[vector]] into a rotation, rot30x<br />
|- valign="top"<br />
| style="white-space: nowrap" |[[vector]] vec30X <br />
| style="white-space: nowrap" |= [[llRot2Euler]](rot30X );<br />
||// convert the rotation back to a [[vector]] (the values will be in radians)<br />
|}<br />
</div></div><br />
<br />
== Differences between math's quaternions and LSL rotations ==<br />
<br />
There are a few differences between LSL and maths that have little consequences while scripting, but that might puzzle people with prior mathematical knowledge. So we thought it would be good to list them here:<br />
<br />
* In LSL, all quaternions are normalized (the dot product of '''R''' by '''R''' is always '''1'''), and therefore represent ways to rotate objects without changing their size. In maths, generic quaternions might be not normalized, and they represent ''affinities'', i.e. a way to rotate '''and''' change the size of objects.<br />
* In LSL, the '''s''' term is the fourth member of the rotation: '''<x, y, z, s>'''. In maths, the '''s''' term, also called "real part", is written as the first coordinate of the quaternion: '''(s, x, y, z)'''.<br />
* Multiplication is written in reverse order in LSL and in maths. In LSL, you would write '''R * S''', where in maths you would write '''S . R'''.<br />
<br />
== Order of rotation for Euler Vectors ==<br />
<br />
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.<br />
<br />
== Local vs Global (World) rotations ==<br />
<br />
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.<br />
<br />
'''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.<br />
<br />
In LSL, the difference between doing a '''local''' or '''global''' rotation is the order the '''rotations''' are evaluated in the statement.<br />
<br />
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. <br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation localRot = <br />
| style="white-space: nowrap" |rot30X * myRot;<br />
||// do a local rotation by multiplying a constant rotation by a world rotation<br />
|}<br />
</div></div><br />
<br />
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.<br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation globalRot <br />
| style="white-space: nowrap" | = myRot * rot30X;<br />
||// do a global rotation by multiplying a world rotation by a constant rotation<br />
|}<br />
</div></div><br />
<br />
== Another way to think about combining rotations ==<br />
<br />
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.<br />
<br />
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.<br />
<br />
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.<br />
<br />
'''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'''.<br />
<br />
==Using Rotations ==<br />
<br />
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 [[float]]s, but there is overhead in unpacking them.<br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rot30X <br />
| style="white-space: nowrap" |= [[llEuler2Rot]](<30, 0, 0> * [[#DEG_TO_RAD|DEG_TO_RAD]] );<br />
||// Create a rotation constant<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rotCopy <br />
| style="white-space: nowrap" |= rot30X;<br />
||// Just copy it into rotCopy, it copies all 4 float components<br />
|- valign="top"<br />
| style="white-space: nowrap" |float X <br />
| style="white-space: nowrap" |= rotCopy.x;<br />
||// Get out the individual components of the rotation<br />
|- valign="top"<br />
| style="white-space: nowrap" |float Y <br />
| style="white-space: nowrap" |= rotCopy.y;<br />
||<br />
|- valign="top"<br />
| style="white-space: nowrap" |float Z <br />
| style="white-space: nowrap" |= rotCopy.z;<br />
||<br />
|- valign="top"<br />
| style="white-space: nowrap" |float S <br />
| style="white-space: nowrap" |= rotCopy.s;<br />
||<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation anotherCopy <br />
| style="white-space: nowrap" |= <X, Y, Z, S>;<br />
||// Make another rotation out of the components<br />
|}<br />
</div></div><br />
<br />
<br />
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.<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rot330X <br />
| style="white-space: nowrap" |= <-rot30X.x, -rot30X.y, -rot30X.z, rot30X.s>;<br />
||// invert a rotation - NOTE the s component isn't negated<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation another330X <br />
| style="white-space: nowrap" |= [[#ZERO_ROTATION|ZERO_ROTATION]] / rot30X;<br />
||// invert a rotation by division, same result as rot330X<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation yetanother330X <br />
| style="white-space: nowrap" |= <rot30X.x, rot30X.y, rot30X.z, -rot30X.s>;<br />
||// not literally the same but works the same.<br />
|}<br />
</div></div><br />
<br />
==Single or Root Prims vs Linked Prims vs Attachments ==<br />
<br />
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.<br />
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.<br />
<br />
{{LSLRotGetSet}}<br />
<br />
==Rotating Vectors ==<br />
<br />
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.<br />
<br />
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 [[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.<br />
=== Position of Object Rotated Around A Relative Point ===<br />
<lsl>rotation vRotArc = llEuler2Rot( <30.0, 0.0, 0.0> * DEG_TO_RAD );<br />
//-- creates a rotation constant, 30 degrees around the X axis<br />
<br />
vector vPosOffset = <0.0, 1.0, 0.0>;<br />
//-- creates an offset one meter in the positive Y direction<br />
<br />
vector vPosRotOffset = vPosOffset * vRotArc;<br />
//-- rotates the offset to get the motion caused by the rotation<br />
<br />
vector vPosOffsetDiff = vPosOffset - vPosRotOffset;<br />
//-- gets the local difference between the current offset and the rotated one<br />
<br />
vector vPosRotDiff = vPosOffsetDiff * llGetRot();<br />
//-- rotates the difference in the offsets to be relative to the global rotation.<br />
<br />
vector vPosNew = llGetPos() + vPosRotDiff;<br />
//-- finds the prims new position by adding the rotated offset difference<br />
<br />
rotation vRotNew = vRotArc * llGetRot();<br />
//-- finds rot to continue facing offset point</lsl><br />
:in application, the same action as:<br />
<lsl>llSetPrimitiveParams( [PRIM_POSITION, llGetPos() + (vPosOffset - vPosOffset * vRotArc) * llGetRot(),<br />
PRIM_ROTATION, vRotArc * llGetRot()] );</lsl><br />
* The above method results in the orbiting object always having the same side facing the center. An alternative that preserves the orbiters rotation is as follows<br />
<lsl>llSetPrimitiveParams( [PRIM_POSITION, llGetPos() + (vPosOffset - vPosOffset * vRotArc) * llGetRot()];<br />
vPosOffset = vPosOffset * vRotArc;</lsl><br />
'''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. Also to get a full orbit, you'll need to repeat the listed steps (in a [[timer]] perhaps).<br />
<br />
=== Position of Relative Point Around Rotated Object ===<br />
To get a point relative to the objects current facing (such as used in rezzors)<br />
<lsl>vector vPosOffset = <0.0, 0.0, 1.0>;<br />
//-- creates an offset one meter in the positive Z direction.<br />
<br />
vector vPosRotOffset = vPosOffset * llGetRot();<br />
//-- rotate the offset to be relative to objects rotation<br />
<br />
vector vPosOffsetIsAt = llGetPos() + vPosRotOffset;<br />
//-- get the region position of the rotated offset</lsl><br />
:in application, the same action as:<br />
<lsl>llRezAtRoot( "Object", llGetPos() + vPosOffset * llGetRot(), ZERO_VECTOR, llGetRot(), 0 );</lsl><br />
<br />
==Useful Snippets==<br />
<lsl>integer IsRotation(string s)<br />
{<br />
list split = llParseString2List(s, [" "], ["<", ">", ","]);<br />
if(llGetListLength(split) != 9)//we must check the list length, or the next test won't work properly.<br />
return 0;<br />
return !((string)((rotation)s) == (string)((rotation)((string)llListInsertList(split, ["-"], 7))));<br />
//it works by trying to flip the sign on the S element of the rotation,<br />
//if it works or breaks the rotation then the values won't match.<br />
//if the rotation was already broken then the sign flip will have no affect and the values will match<br />
//we cast back to string so we can catch negative zero which allows for support of <0,0,0,0><br />
}//Strife Onizuka</lsl><br />
<br />
<br />
// Calculate a point at distance d in the direction the avatar id is facing<br />
<lsl>vector point_in_front_of( key id, float d )<br />
{<br />
list pose = llGetObjectDetails( id, [ OBJECT_POS, OBJECT_ROT ] );<br />
return ( llList2Vector( pose, 0 ) + < d, 0.0, 0.0 > * llList2Rot( pose, 1 ) );<br />
}// Mephistopheles Thalheimer</lsl><br />
<br />
<br />
// Rez an object o at a distance d from the end of the z axis.<br />
// The object is rezzed oriented to the rezzer<br />
<br />
<lsl>rez_object_at_end( string o, float d )<br />
{<br />
vector s = llGetScale();<br />
<br />
if( llGetInventoryType( o ) == INVENTORY_OBJECT )<br />
{<br />
llRezObject( o, llGetPos() + llRot2Up( llGetRot() ) * ( s.z / 2.0 + d ) , ZERO_VECTOR, llGetRot(), 0 );<br />
}<br />
}// Mephistopheles Thalheimer</lsl><br />
<br />
// Useful functions converted to LSL from [http://www.isner.com/tutorials/quatSpells/quaternion_spells_12.htm this page]:<br />
<br />
// Scale a rotation:<br />
<lsl>rotation ScaleQuat(rotation source, float ratio)<br />
{<br />
return llAxisAngle2Rot(llRot2Axis(source), ratio * llRot2Angle(source));<br />
}</lsl><br />
<br />
// Constrain a rotation to a given plane, defined by its normal, this is very useful for vehicles that remain horizontal in turns:<br />
<lsl>rotation ConstrainQuat2Plane(rotation source, vector normal)<br />
{<br />
return llAxisAngle2Rot(normal, <source.x, source.y, source.z> * normal * llRot2Angle(source));<br />
} // Jesrad Seraph</lsl><br />
<br />
// Slerp (rotation combination) function from [[Slerp]]:<br />
<lsl>rotation BlendQuats(rotation a, rotation b, float ratio)<br />
{<br />
return llAxisAngle2Rot(llRot2Axis(b /= a), ratio * llRot2Angle(b)) * a;<br />
}</lsl><br />
<br />
== Constants ==<br />
=== [[ZERO_ROTATION]] ===<br />
ZERO_ROTATION = <0.0, 0.0, 0.0, 1.0>;<br/><br />
A rotation constant representing a Euler angle of <0.0, 0.0, 0.0>.<br />
<br />
=== [[DEG_TO_RAD]] ===<br />
DEG_TO_RAD = 0.01745329238f;<br/><br />
A float constant that when multiplied by an angle in degrees gives the angle in radians.<br />
<br />
=== [[RAD_TO_DEG]] ===<br />
RAD_TO_DEG = 57.29578f;<br/><br />
A float constant when multiplied by an angle in radians gives the angle in degrees.<br />
<br />
<br />
[[Category:LSL_Types|Rotation]][[Category:LSL_Math]][[Category:LSL_Math/3D]][[Category:LSL Rotation]]</div>Jonno Stromfieldhttps://wiki.secondlife.com/wiki/RotationRotation2009-10-21T10:12:29Z<p>Jonno Stromfield: /* Euler vector */</p>
<hr />
<div>{{LSL Header|ml=*}}{{RightToc}}<br />
==Rotation==<br />
The LSL '''rotation''' type is one of several ways to represent an orientation in 3D. (Note that we try to write the type name in '''bold'''.)<br />
It is a mathematical object called a {{LSLG|quaternion}}. You can think of a quaternion as four numbers, three of which represent the direction an object is facing and a fourth that represents the object's banking left or right around that direction. The main advantage of using <br />
quaternions is that they are not susceptible to [http://en.wikipedia.org/wiki/Gimbal_Lock gimbal lock]. <br />
For the complex inner workings of quaternion mathematics, see {{LSLG|quaternion}}. <br />
For a list of functions and events related to rotations see {{LSLG|LSL Rotation Synopsis}}.<br />
There is also information about causing textures to rotate in {{LSLG|texture}}s.<br />
<br />
==Other representations==<br />
===Euler vector===<br />
Another way to represent a 3D angle is using three numbers, <X, Y, Z>, which represent the amount which the object is rotated around each axis. This is used in the Edit window, for example, and is generally easy for people to visualize. It is easy to adjust the Rotation <x, y, z> numbers in the Edit window and see how the object behaves. Note that in the Edit window, the numbers are in degrees, that is, a right angle is 90.<br />
<br />
In LSL, these three angles are expressed in [[radians]] instead of degrees, that is, a right angle is PI/2. (A radian is sort of a very fat degree.)<br />
Note that these three numbers are a '''vector''' type and not a '''rotation''' type, though it can represent the same information. This is called the ''Euler'' representation of a 3D angle. In LSL the rotation around x is done first, then around y, and finally around z.<br />
<br />
===FWD, LEFT, UP=== <br />
Another way to represent the same 3D angle is to use three vectors, showing what the front is pointing at (fwd), what the top is pointing at (up), and what the left side is pointing at (left). Actually, only two of the three are needed, because any two determines the third. <br />
<br />
For good reasons, such as being able to easily combine rotations, the four number version, the '''rotation''', is better, though perhaps harder for a beginner to grasp. Fortunately it's very seldom necessary to do anything with the actual internal representation of ''rotations'' and there are functions for converting easily back and forth between the three LSL types, and between degrees and radians.<br />
<br />
==Right hand rule==<br />
In LSL all rotations are done according to the '''right hand rule'''. With your right hand, extend the first finger in the direction of the positive direction of the x-axis. Extend your second finger at right angles to your first finger, it will point along the positive y-axis, and your thumb, extended at right angles to both will point along the 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).<br />
<br />
http://en.wikipedia.org/wiki/Right_hand_rule<br />
<br />
Now, don't remove your right hand just yet, there is another use for it, determining the direction of a positive rotation. Make a fist with your right hand, thumb extended and pointing in the positive direction of the axis you are interested in. Your fingers curl around in the direction of positive rotation. Rotations around the X, Y, and Z axis are often referred to as Roll, Pitch, and Yaw, particularly for vehicles.<br />
<br />
[http://en.wikipedia.org/wiki/Tait-Bryan_angles Roll Pitch Yaw]<br />
<br />
== Combining Rotations ==<br />
'<br />
Suppose you have two rotations. ''r1'' is rotate 90 degrees to the left, and ''r2'' is rotate 30 degrees to the right. (Any rotations will work; these are just an example.)<br />
You can combine ''r1'' and ''r2'' to make ''r3'' using the '''*''' operator. It doesn't really multiply them, it ''composes'' them.<br />
<lsl><br />
rotation r3 = r1 * r2;<br />
</lsl><br />
The result in this case is that ''r3'' means rotate 60 degrees to the left.<br />
<br />
In other words, 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. The '''multiply''' operation applies the rotation in the positive direction, the '''divide''' operation does a negative rotation. You can also negate a rotation directly, just negate the s component, e.g. X.s = -X.s.<br />
<br />
Unlike other types such as {{LSLG|float}}, the order in which the operations are done, <br />
[http://en.wikipedia.org/wiki/Commutative non-commutative], is important.<br />
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.<br />
<br />
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.<br />
<br />
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.<br />
<br />
Clearly this is a different result from the first rotation, but the order of rotation is the only thing changed.<br />
<br />
To do a constant rotation you need to define a '''rotation''' value which can be done by creating a {{LSLG|vector}} with the X, Y, Z angles in radians as components (called an Euler angle), then converting that to a '''rotation''' by using the {{LSLG|llEuler2Rot}} function. You can alternately create the native rotation directly: the real part is the cosine of half the angle of rotation, and the vector part is the normalized axis of rotation multiplied by the sine of half the angle of rotation. To go from a rotation to an Euler angle {{LSLG|vector}} use {{LSLG|llRot2Euler}}.<br />
<br />
'''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:<br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rot30X<br />
| style="white-space: nowrap" |= [[llEuler2Rot]](<30, 0, 0> * [[DEG_TO_RAD]]);<br />
||// convert the degrees to radians, then convert that [[vector]] into a rotation, rot30x<br />
|- valign="top"<br />
| style="white-space: nowrap" |[[vector]] vec30X <br />
| style="white-space: nowrap" |= [[llRot2Euler]](rot30X );<br />
||// convert the rotation back to a [[vector]] (the values will be in radians)<br />
|}<br />
</div></div><br />
<br />
== Differences between math's quaternions and LSL rotations ==<br />
<br />
There are a few differences between LSL and maths that have little consequences while scripting, but that might puzzle people with prior mathematical knowledge. So we thought it would be good to list them here:<br />
<br />
* In LSL, all quaternions are normalized (the dot product of '''R''' by '''R''' is always '''1'''), and therefore represent ways to rotate objects without changing their size. In maths, generic quaternions might be not normalized, and they represent ''affinities'', i.e. a way to rotate '''and''' change the size of objects.<br />
* In LSL, the '''s''' term is the fourth member of the rotation: '''<x, y, z, s>'''. In maths, the '''s''' term, also called "real part", is written as the first coordinate of the quaternion: '''(s, x, y, z)'''.<br />
* Multiplication is written in reverse order in LSL and in maths. In LSL, you would write '''R * S''', where in maths you would write '''S . R'''.<br />
<br />
== Order of rotation for Euler Vectors ==<br />
<br />
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.<br />
<br />
== Local vs Global (World) rotations ==<br />
<br />
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.<br />
<br />
'''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.<br />
<br />
In LSL, the difference between doing a '''local''' or '''global''' rotation is the order the '''rotations''' are evaluated in the statement.<br />
<br />
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. <br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation localRot = <br />
| style="white-space: nowrap" |rot30X * myRot;<br />
||// do a local rotation by multiplying a constant rotation by a world rotation<br />
|}<br />
</div></div><br />
<br />
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.<br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation globalRot <br />
| style="white-space: nowrap" | = myRot * rot30X;<br />
||// do a global rotation by multiplying a world rotation by a constant rotation<br />
|}<br />
</div></div><br />
<br />
== Another way to think about combining rotations ==<br />
<br />
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.<br />
<br />
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.<br />
<br />
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.<br />
<br />
'''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'''.<br />
<br />
==Using Rotations ==<br />
<br />
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 [[float]]s, but there is overhead in unpacking them.<br />
<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rot30X <br />
| style="white-space: nowrap" |= [[llEuler2Rot]](<30, 0, 0> * [[#DEG_TO_RAD|DEG_TO_RAD]] );<br />
||// Create a rotation constant<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rotCopy <br />
| style="white-space: nowrap" |= rot30X;<br />
||// Just copy it into rotCopy, it copies all 4 float components<br />
|- valign="top"<br />
| style="white-space: nowrap" |float X <br />
| style="white-space: nowrap" |= rotCopy.x;<br />
||// Get out the individual components of the rotation<br />
|- valign="top"<br />
| style="white-space: nowrap" |float Y <br />
| style="white-space: nowrap" |= rotCopy.y;<br />
||<br />
|- valign="top"<br />
| style="white-space: nowrap" |float Z <br />
| style="white-space: nowrap" |= rotCopy.z;<br />
||<br />
|- valign="top"<br />
| style="white-space: nowrap" |float S <br />
| style="white-space: nowrap" |= rotCopy.s;<br />
||<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation anotherCopy <br />
| style="white-space: nowrap" |= <X, Y, Z, S>;<br />
||// Make another rotation out of the components<br />
|}<br />
</div></div><br />
<br />
<br />
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.<br />
<div id="box"><div style="padding: 0.5em"><br />
{| cellpadding=0 cellspacing=0<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation rot330X <br />
| style="white-space: nowrap" |= <-rot30X.x, -rot30X.y, -rot30X.z, rot30X.s>;<br />
||// invert a rotation - NOTE the s component isn't negated<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation another330X <br />
| style="white-space: nowrap" |= [[#ZERO_ROTATION|ZERO_ROTATION]] / rot30X;<br />
||// invert a rotation by division, same result as rot330X<br />
|- valign="top"<br />
| style="white-space: nowrap" |rotation yetanother330X <br />
| style="white-space: nowrap" |= <rot30X.x, rot30X.y, rot30X.z, -rot30X.s>;<br />
||// not literally the same but works the same.<br />
|}<br />
</div></div><br />
<br />
==Single or Root Prims vs Linked Prims vs Attachments ==<br />
<br />
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.<br />
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.<br />
<br />
{{LSLRotGetSet}}<br />
<br />
==Rotating Vectors ==<br />
<br />
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.<br />
<br />
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 [[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.<br />
=== Position of Object Rotated Around A Relative Point ===<br />
<lsl>rotation vRotArc = llEuler2Rot( <30.0, 0.0, 0.0> * DEG_TO_RAD );<br />
//-- creates a rotation constant, 30 degrees around the X axis<br />
<br />
vector vPosOffset = <0.0, 1.0, 0.0>;<br />
//-- creates an offset one meter in the positive Y direction<br />
<br />
vector vPosRotOffset = vPosOffset * vRotArc;<br />
//-- rotates the offset to get the motion caused by the rotation<br />
<br />
vector vPosOffsetDiff = vPosOffset - vPosRotOffset;<br />
//-- gets the local difference between the current offset and the rotated one<br />
<br />
vector vPosRotDiff = vPosOffsetDiff * llGetRot();<br />
//-- rotates the difference in the offsets to be relative to the global rotation.<br />
<br />
vector vPosNew = llGetPos() + vPosRotDiff;<br />
//-- finds the prims new position by adding the rotated offset difference<br />
<br />
rotation vRotNew = vRotArc * llGetRot();<br />
//-- finds rot to continue facing offset point</lsl><br />
:in application, the same action as:<br />
<lsl>llSetPrimitiveParams( [PRIM_POSITION, llGetPos() + (vPosOffset - vPosOffset * vRotArc) * llGetRot(),<br />
PRIM_ROTATION, vRotArc * llGetRot()] );</lsl><br />
* The above method results in the orbiting object always having the same side facing the center. An alternative that preserves the orbiters rotation is as follows<br />
<lsl>llSetPrimitiveParams( [PRIM_POSITION, llGetPos() + (vPosOffset - vPosOffset * vRotArc) * llGetRot()];<br />
vPosOffset = vPosOffset * vRotArc;</lsl><br />
'''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. Also to get a full orbit, you'll need to repeat the listed steps (in a [[timer]] perhaps).<br />
<br />
=== Position of Relative Point Around Rotated Object ===<br />
To get a point relative to the objects current facing (such as used in rezzors)<br />
<lsl>vector vPosOffset = <0.0, 0.0, 1.0>;<br />
//-- creates an offset one meter in the positive Z direction.<br />
<br />
vector vPosRotOffset = vPosOffset * llGetRot();<br />
//-- rotate the offset to be relative to objects rotation<br />
<br />
vector vPosOffsetIsAt = llGetPos() + vPosRotOffset;<br />
//-- get the region position of the rotated offset</lsl><br />
:in application, the same action as:<br />
<lsl>llRezAtRoot( "Object", llGetPos() + vPosOffset * llGetRot(), ZERO_VECTOR, llGetRot(), 0 );</lsl><br />
<br />
==Useful Snippets==<br />
<lsl>integer IsRotation(string s)<br />
{<br />
list split = llParseString2List(s, [" "], ["<", ">", ","]);<br />
if(llGetListLength(split) != 9)//we must check the list length, or the next test won't work properly.<br />
return 0;<br />
return !((string)((rotation)s) == (string)((rotation)((string)llListInsertList(split, ["-"], 7))));<br />
//it works by trying to flip the sign on the S element of the rotation,<br />
//if it works or breaks the rotation then the values won't match.<br />
//if the rotation was already broken then the sign flip will have no affect and the values will match<br />
//we cast back to string so we can catch negative zero which allows for support of <0,0,0,0><br />
}//Strife Onizuka</lsl><br />
<br />
<br />
// Calculate a point at distance d in the direction the avatar id is facing<br />
<lsl>vector point_in_front_of( key id, float d )<br />
{<br />
list pose = llGetObjectDetails( id, [ OBJECT_POS, OBJECT_ROT ] );<br />
return ( llList2Vector( pose, 0 ) + < d, 0.0, 0.0 > * llList2Rot( pose, 1 ) );<br />
}// Mephistopheles Thalheimer</lsl><br />
<br />
<br />
// Rez an object o at a distance d from the end of the z axis.<br />
// The object is rezzed oriented to the rezzer<br />
<br />
<lsl>rez_object_at_end( string o, float d )<br />
{<br />
vector s = llGetScale();<br />
<br />
if( llGetInventoryType( o ) == INVENTORY_OBJECT )<br />
{<br />
llRezObject( o, llGetPos() + llRot2Up( llGetRot() ) * ( s.z / 2.0 + d ) , ZERO_VECTOR, llGetRot(), 0 );<br />
}<br />
}// Mephistopheles Thalheimer</lsl><br />
<br />
// Useful functions converted to LSL from [http://www.isner.com/tutorials/quatSpells/quaternion_spells_12.htm this page]:<br />
<br />
// Scale a rotation:<br />
<lsl>rotation ScaleQuat(rotation source, float ratio)<br />
{<br />
return llAxisAngle2Rot(llRot2Axis(source), ratio * llRot2Angle(source));<br />
}</lsl><br />
<br />
// Constrain a rotation to a given plane, defined by its normal, this is very useful for vehicles that remain horizontal in turns:<br />
<lsl>rotation ConstrainQuat2Plane(rotation source, vector normal)<br />
{<br />
return llAxisAngle2Rot(normal, <source.x, source.y, source.z> * normal * llRot2Angle(source));<br />
} // Jesrad Seraph</lsl><br />
<br />
// Slerp (rotation combination) function from [[Slerp]]:<br />
<lsl>rotation BlendQuats(rotation a, rotation b, float ratio)<br />
{<br />
return llAxisAngle2Rot(llRot2Axis(b /= a), ratio * llRot2Angle(b)) * a;<br />
}</lsl><br />
<br />
== Constants ==<br />
=== [[ZERO_ROTATION]] ===<br />
ZERO_ROTATION = <0.0, 0.0, 0.0, 1.0>;<br/><br />
A rotation constant representing a Euler angle of <0.0, 0.0, 0.0>.<br />
<br />
=== [[DEG_TO_RAD]] ===<br />
DEG_TO_RAD = 0.01745329238f;<br/><br />
A float constant that when multiplied by an angle in degrees gives the angle in radians.<br />
<br />
=== [[RAD_TO_DEG]] ===<br />
RAD_TO_DEG = 57.29578f;<br/><br />
A float constant when multiplied by an angle in radians gives the angle in degrees.<br />
<br />
<br />
[[Category:LSL_Types|Rotation]][[Category:LSL_Math]][[Category:LSL_Math/3D]][[Category:LSL Rotation]]</div>Jonno Stromfieldhttps://wiki.secondlife.com/wiki/PrimsPrims2009-10-02T07:43:12Z<p>Jonno Stromfield: /* Introduction */</p>
<hr />
<div>{{Otheruses4|primitives|[[LSL]] related information|:Category:LSL Prim}}<br />
<br />
<br />
==Introduction==<br />
This page is mostly about how primitives are implemented in the server and viewer code. It might help users of the in-world build tool understand the use of the many options. An excellent detailed summary can be found here. [http://www.realityprime.com/articles/how-sl-primitives-really-work]<br />
<br />
Primitives in Second Life are constructed by starting with a basic two dimensional shape, modifying it, and extruding it in to the third dimension along a path while applying modifications to the extrusion. The most basic example is a cube which starts out as a 2D square and extrudes along a linear path with no modifications to make a cube. A cylinder starts out as as circle and extrudes along the same linear path. If the circle was extruded along a circular path you would create a torus, and if a half-circle is extruded along another type of circular path you create a sphere.<br />
<br />
==2D Shape (Profile)==<br />
<br />
* ProfileCurve<br />
** Two combined enums: the lower 4 bits define the outer profile shape, and the high 4 bits define the type of hole if ProfileHollow is non-zero<br />
<pre><br />
Profile Shape:<br />
Circle = 0x00<br />
Square = 0x01<br />
Isometric Triangle = 0x02<br />
Equilateral Triangle = 0x03<br />
Right Triangle = 0x04<br />
Half Circle = 0x05<br />
</pre><br />
<br />
<pre><br />
Hole Shape:<br />
Same = 0x00<br />
Circle = 0x10<br />
Square = 0x20<br />
Triangle = 0x30<br />
</pre><br />
<br />
===2D Shape (Profile) Modifications===<br />
<br />
* ProfileBegin<br />
** Where the cut (if any) in the profile begins<br />
* ProfileEnd<br />
** Where the cut (if any) in the profile ends<br />
* ProfileHollow<br />
** How much of the profile is hollowed out, as a percent of the original bounding box. If non-zero this creates a hole using the shape defined in the higher bits of ProfileCurve<br />
<br />
==Extrusion (Path)==<br />
<br />
* PathCurve<br />
** Enum for the extrusion path. For whatever reason only the upper bits are used in this field:<br />
<br />
<pre><br />
Line = 0x10<br />
Circle = 0x20<br />
Circle2 = 0x30<br />
Test = 0x40 // ???<br />
Flexible = 0x80<br />
</pre><br />
<br />
===Extrusion (Path) Modifications===<br />
<br />
* PathBegin<br />
* PathEnd<br />
* PathScaleX<br />
* PathScaleY<br />
* PathShearX<br />
* PathShearY<br />
* PathTwistBegin<br />
* PathTwist<br />
* PathRadiusOffset<br />
* PathTaperX<br />
* PathTaperY<br />
* PathRevolutions<br />
* PathSkew</div>Jonno Stromfieldhttps://wiki.secondlife.com/wiki/Talk:RotationTalk:Rotation2009-09-11T11:07:49Z<p>Jonno Stromfield: /* With regard to rotations of a child of an attachment */</p>
<hr />
<div>{{Talk}}<br />
Fixed a few minor syntax errors and reworked the top of the article a bit. As an article it is quite far along though it still has a ways to go. [[User:Strife Onizuka|Strife Onizuka]] 03:32, 29 January 2007 (PST)<br />
<br />
== Intro is awful ==<br />
<br />
"gymbal lock" is something that affects mechanical systems with gyroscopes. A quaternion rotation is a mathematical abstraction. The term simply does not apply, and only serves to confuse things. The reference to "SLERP" without a link is useless. [[User:Doran Zemlja|Doran Zemlja]]<br />
<br />
:Gimbal lock effects Euler angles to which you wrote an article using them everywhere without mention it; it is a gross oversight. That sentence is a bit complex on review and yes there is no SLERP article but that doesn't mean someone won't write one (it is better to leave open links then no links; no links give no hint that a page should be created). I may write a short one tomorrow, I already have a function that implements it (I've just been pressed for time). I will find a better article on gimbal lock, the wikipedia one is pretty poor in this regard as it fails to go into the programing implications. I gave you the benefit of the doubt and looked up 'gymbal' in the dictionary, to which it was nowhere to be found; but 'gimbal' was. [[User:Strife Onizuka|Strife Onizuka]] 19:33, 31 January 2007 (PST)<br />
<br />
::Gimbal lock affects you every time you use Euler Coordinates, it is not restricted to gyroscopes. German article on wikipedia about gimbal lock shows it much more clearly than the English version -- Catherine Pfeffer 2007-12-08<br />
<br />
I'm a mathematician, and think the following text is also misleading (or partially incorrect) in the '''Other Representations''' section: '''''"Another way to represent a rotation is using three numbers, <X, Y, Z>, which represent the amount (in radians) which the object is rotated around each axis. This is used in the Edit window..."''''' Technically, 1 "radian" equals the angle that is traced out by an arc along a circle's circumference, [[when that arc equals the circle's radius]]. This means that 2*pi radians equals 360 degrees, 1*pi radians equals 180 degrees, and pi/2 radians equals 90 degrees. SL's '''prim'''-editing window displays rotations in [[degrees]] (360, 180, 90...) and NOT in [[radians]] (2pi, pi, pi/2)! However, it IS true that radians must be used when editing values in some LSL '''script''' commands! [[User:Times Sands|Times Sands]] 18:18, 10 November 2008 (UTC)<br />
<br />
== Mirroring using quaternions ==<br />
<br />
I think I have worked out how to mirror a point (and therefore an entire object in pieces,) using quaternions, but does anyone here know how to, or if it is even possible to, define a rotation that turns a left hand into a right hand or vise-versa? This is a three diminsional mirror operation, but in four diminsions it is a simple rotation. (I could be wrong, but based on my research into quaternions it seems right...)<br />[[User:Cron Stardust|Cron Stardust]] 22:16, 25 March 2007 (PDT)<br />
:It depends entirely upon which axis you want to mirror around. Save yourself some work and look up Jeffrey's Prim Mirror. [[User:Strife Onizuka|Strife Onizuka]] 11:13, 26 March 2007 (PDT)<br />
<br />
== Moving this page ==<br />
<br />
Shouldn't the content of this page be moved to Category:LSL Rotation? It seems confusing to me to have multiple Rotation pages.<br />
<br />
:Good point, I see no problem merging them. -- [[User:Strife Onizuka|Strife Onizuka]] 08:40, 22 July 2007 (PDT)<br />
<br />
::Very true. Or even better, do a "pure maths" one and a "pure lsl" one -- Catherine Pfeffer, 2007-12-08<br />
<br />
== GetRot()/SetRot() chart ==<br />
<br />
llGetLocalRot() and llGetRot() clearly do *not* return the same value in the root prim of an attachment. While I believe that llGetRot() returns the avatar rotation as indicated, llGetLocalRot() I believe gives the rotation of the root prim relative to the attachment point (or the avatar?)<br />
<br />
:You are correct, that entry in the table is wrong. -- [[User:Strife Onizuka|Strife Onizuka]] 08:40, 22 July 2007 (PDT)<br />
<br />
== Visual aids ==<br />
<br />
I use [http://www.isner.com/tutorials/quatSpells/quaternion_spells_14.htm this page] as a visual reference and cheat sheet for quaternion operations. --[[User:Tateru Nino|Tateru Nino]] 15:53, 9 September 2007 (PDT)<br />
<br />
== Maths versus LSL ==<br />
<br />
Has anyone noticed that maths' quaternion multiplication is written in reverse order than in LSL ? That is, what you write Q1 . Q2 in maths is computed in LSL with Q2 * Q1. Is that a bug or simply a documentation issue ? -- Catherine Pfeffer - 2007-12-08<br />
<br />
:It appears to be a bug, with an obvious patch in the server code, but this bug won't be fixed, so I decided to document the problem here -- Catherine Pfeffer - 2008-08-28<br />
<br />
::I know it's a way late comment, but my guess is that it's the noticable side effect of LSL's backwards order of evaluation. we just don't notice it elsewhere because most other operations within lsl are communicative and quaternion math isn't.<br/>-- '''[[User:Void_Singer|Void]]''' <sup><small>([[User_talk:Void_Singer|talk]]|[[Special:Contributions/Void_Singer|contribs]])</small></sup> 11:09, 19 May 2009 (UTC)<br />
<br />
== Unjustified preference for Euler notation ==<br />
<br />
One thing that really annoys me with this page is that it seems to consider that the Euler coordinates are the easy way to deal with rotations, while the <x, y, z, s> quaternion representation is almost unintelligible.<br />
<br />
That's a common opinon, and as a matter of facts, most LSL scripts I have found use and overuse llEuler2Rot() and llRot2Euler().<br />
<br />
But that's simply wrong. Euler's notation is completly unintuitive for any non-trivial situation.<br />
<br />
To get convinced of it, try to figure out the Euler angles for the rotation of 45 degrees around XY diagonal (X = Y and Z = 0). Good luck ! :-).<br />
Now try figuring out the quaternions's values with the directing vector and sine and cosine of the half-angle: that's straightforward.<br />
<br />
I think this page is misleading a lot of new scripters into the wrong direction because of its preference for Euler angles. -- Catherine Pfeffer - 2008-08-28<br />
<br />
:I agree. '''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 14:19, 28 August 2008 (PDT)<br />
<br />
== Rotating Vectors ==<br />
<br />
The example:-<br />
<br />
//-- same as:<br />
llSetPrimitiveParams( [PRIM_POSITION, llGetPos() + (gPosOffset - gPosOffset * gRotArc) * llGetRot(),PRIM_ROTATION, gRotArc * llGetRot()] );<br />
<br />
gives no derivation of the variables gPosOffset and gRotArc.<br />
Which is less than useful to someone learning from the text.<br />
[[User:Gregory McLeod|Gregory McLeod]] 08:51, 1 September 2008 (PDT)<br />
:missed this comment before. although it should be guessable that offset = gPosOffset, and rot6x = gRotArc, I went ahead and made the section more explicit, and converted it to use lsl highlighting (so that all keywords would be linked) and removed a few slightly misleading viewer frame references. <br/>-- '''[[User:Void_Singer|Void]]''' <sup><small>([[User_talk:Void_Singer|talk]]|[[Special:Contributions/Void_Singer|contribs]])</small></sup> 11:00, 19 May 2009 (UTC)<br />
<br />
== Useful snippets ==<br />
<br />
The snippet we have now is kind of a string function. [http://www.isner.com/tutorials/quatSpells/quaternion_spells_12.htm How about converting these] from XSI to LSL? <br />
<br />
[http://lslwiki.net/lslwiki/wakka.php?wakka=LibraryRotationFunctions How about these] from lslwiki.net? ("All functions on this page are released into public domain and may have been based off other public domain works.")<br />
<br />
By the way, someone above complained about an unlinked reference to slerp() which seems to now be completely missing(!) Both of those have slerp(). [[User:Gia May|Gia May]] 07:15, 8 December 2008 (UTC)<br />
<br />
:I offer L$5000 to the first person who translates two functions from http://www.isner.com/tutorials/quatSpells/quaternion_spells_12.htm to the Useful snippets here, or for code constraining rotations to an arbitrary conic section. Runners up, if any, will be awarded on merit, and I am also asking the Lindens to help with this library deficiency bug bounty. IM me inworld for details. [[User:JS Uralia|JS Uralia]] 21:17, 2 February 2009 (UTC)<br />
::Hello, I went ahead and added three such functions: ConstrainQuaternion2Plane, ScaleQuaternion and CombineQuaternions (Slerp) though this last one already existed on the Wiki.--[[User:Jesrad Seraph|Jesrad Seraph]] 07:05, 17 May 2009 (UTC)<br />
<br />
Pending fulfillment of my promise to pay Jesrad L$5000 -- and [http://wiki.secondlife.com/w/index.php?title=Rotation&diff=220643&oldid=167253 Mephistopheles Thalheimer can attest I keep my word on these bounty payments] -- could someone please independently verify that this function works as it should?<br />
<br />
<lsl>// Constrain a rotation to a given plane, defined by its normal, this is very useful for vehicles that remain horizontal in turns:<br />
rotation ConstrainQuat2Plane(rotation source, vector normal)<br />
{<br />
return llAxisAngle2Rot(normal, <source.x, source.y, source.z> * normal * llRot2Angle(source));<br />
} // Jesrad Seraph</lsl><br />
<br />
I'm very troubled by the use of the first three elements of the quaternion in that manner, but in all honestly, I don't know enough to figure out what a correct answer is. [[User:JS Uralia|JS Uralia]] 20:43, 23 May 2009 (UTC)<br />
<br />
:I think it might just be correct. I can't verify it at the moment but the math looks to have the correct properties though the magnitudes of the vectors going into the dot product worry me. I'm wondering if <source.x, source.y, source.z> shouldn't be normalized first. On a side note, it doesn't handle the edge cases where source and normal haven't been normalized. -- '''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 09:56, 24 May 2009 (UTC)<br />
::More testing shows it is off by sometimes as much as 90 degrees... I will try to correct it, probably by normalizing the vector part first like suggested.--[[User:Jesrad Seraph|Jesrad Seraph]] 14:52, 7 July 2009 (UTC)<br />
<br />
== With regard to rotations of a child of an attachment ==<br />
<br />
I blow a raspberry at lsl. -- '''[[User:EddyFragment Robonaught|Eddy]]''' <sup><small>([[User talk:EddyFragment_Robonaught|talk]]|[[Special:Contributions/EddyFragment_Robonaught|contribs]])</small></sup> 06:37, 13 July 2009 (UTC)<br />
<br />
:Don't you just love {{Jira|SVC-93}}? Gage me with a spoon *rolls eyes*. -- '''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 18:08, 13 July 2009 (UTC)<br />
<br />
Ah. Not just me then. I thought I just needed a degree in quantum maths to understand it. Thanx for the link. *voted* -- '''[[User:EddyFragment Robonaught|Eddy]]''' <sup><small>([[User talk:EddyFragment_Robonaught|talk]]|[[Special:Contributions/EddyFragment_Robonaught|contribs]])</small></sup> 01:41, 14 July 2009 (UTC)<br />
<br />
<br />
I think this is wrong: it claims that the llGetRot of a child prim of an attached object gives "global rotation of avatar * global rotation of prim (Not Useful)" This would be very useful if it were true and would let you calculate the rotation of the attach point. But I think llGetRot gives you the local rotation of the child prim * global rotation of the avatar, which is of no use that I can think of. I'm new at scripting so I'd appreciate some verification and so won't just change the page. [[User:Jonno Stromfield|Jonno Stromfield]] 11:04, 11 September 2009 (UTC)</div>Jonno Stromfieldhttps://wiki.secondlife.com/wiki/Talk:RotationTalk:Rotation2009-09-11T11:04:10Z<p>Jonno Stromfield: /* With regard to rotations of a child of an attachment */</p>
<hr />
<div>{{Talk}}<br />
Fixed a few minor syntax errors and reworked the top of the article a bit. As an article it is quite far along though it still has a ways to go. [[User:Strife Onizuka|Strife Onizuka]] 03:32, 29 January 2007 (PST)<br />
<br />
== Intro is awful ==<br />
<br />
"gymbal lock" is something that affects mechanical systems with gyroscopes. A quaternion rotation is a mathematical abstraction. The term simply does not apply, and only serves to confuse things. The reference to "SLERP" without a link is useless. [[User:Doran Zemlja|Doran Zemlja]]<br />
<br />
:Gimbal lock effects Euler angles to which you wrote an article using them everywhere without mention it; it is a gross oversight. That sentence is a bit complex on review and yes there is no SLERP article but that doesn't mean someone won't write one (it is better to leave open links then no links; no links give no hint that a page should be created). I may write a short one tomorrow, I already have a function that implements it (I've just been pressed for time). I will find a better article on gimbal lock, the wikipedia one is pretty poor in this regard as it fails to go into the programing implications. I gave you the benefit of the doubt and looked up 'gymbal' in the dictionary, to which it was nowhere to be found; but 'gimbal' was. [[User:Strife Onizuka|Strife Onizuka]] 19:33, 31 January 2007 (PST)<br />
<br />
::Gimbal lock affects you every time you use Euler Coordinates, it is not restricted to gyroscopes. German article on wikipedia about gimbal lock shows it much more clearly than the English version -- Catherine Pfeffer 2007-12-08<br />
<br />
I'm a mathematician, and think the following text is also misleading (or partially incorrect) in the '''Other Representations''' section: '''''"Another way to represent a rotation is using three numbers, <X, Y, Z>, which represent the amount (in radians) which the object is rotated around each axis. This is used in the Edit window..."''''' Technically, 1 "radian" equals the angle that is traced out by an arc along a circle's circumference, [[when that arc equals the circle's radius]]. This means that 2*pi radians equals 360 degrees, 1*pi radians equals 180 degrees, and pi/2 radians equals 90 degrees. SL's '''prim'''-editing window displays rotations in [[degrees]] (360, 180, 90...) and NOT in [[radians]] (2pi, pi, pi/2)! However, it IS true that radians must be used when editing values in some LSL '''script''' commands! [[User:Times Sands|Times Sands]] 18:18, 10 November 2008 (UTC)<br />
<br />
== Mirroring using quaternions ==<br />
<br />
I think I have worked out how to mirror a point (and therefore an entire object in pieces,) using quaternions, but does anyone here know how to, or if it is even possible to, define a rotation that turns a left hand into a right hand or vise-versa? This is a three diminsional mirror operation, but in four diminsions it is a simple rotation. (I could be wrong, but based on my research into quaternions it seems right...)<br />[[User:Cron Stardust|Cron Stardust]] 22:16, 25 March 2007 (PDT)<br />
:It depends entirely upon which axis you want to mirror around. Save yourself some work and look up Jeffrey's Prim Mirror. [[User:Strife Onizuka|Strife Onizuka]] 11:13, 26 March 2007 (PDT)<br />
<br />
== Moving this page ==<br />
<br />
Shouldn't the content of this page be moved to Category:LSL Rotation? It seems confusing to me to have multiple Rotation pages.<br />
<br />
:Good point, I see no problem merging them. -- [[User:Strife Onizuka|Strife Onizuka]] 08:40, 22 July 2007 (PDT)<br />
<br />
::Very true. Or even better, do a "pure maths" one and a "pure lsl" one -- Catherine Pfeffer, 2007-12-08<br />
<br />
== GetRot()/SetRot() chart ==<br />
<br />
llGetLocalRot() and llGetRot() clearly do *not* return the same value in the root prim of an attachment. While I believe that llGetRot() returns the avatar rotation as indicated, llGetLocalRot() I believe gives the rotation of the root prim relative to the attachment point (or the avatar?)<br />
<br />
:You are correct, that entry in the table is wrong. -- [[User:Strife Onizuka|Strife Onizuka]] 08:40, 22 July 2007 (PDT)<br />
<br />
== Visual aids ==<br />
<br />
I use [http://www.isner.com/tutorials/quatSpells/quaternion_spells_14.htm this page] as a visual reference and cheat sheet for quaternion operations. --[[User:Tateru Nino|Tateru Nino]] 15:53, 9 September 2007 (PDT)<br />
<br />
== Maths versus LSL ==<br />
<br />
Has anyone noticed that maths' quaternion multiplication is written in reverse order than in LSL ? That is, what you write Q1 . Q2 in maths is computed in LSL with Q2 * Q1. Is that a bug or simply a documentation issue ? -- Catherine Pfeffer - 2007-12-08<br />
<br />
:It appears to be a bug, with an obvious patch in the server code, but this bug won't be fixed, so I decided to document the problem here -- Catherine Pfeffer - 2008-08-28<br />
<br />
::I know it's a way late comment, but my guess is that it's the noticable side effect of LSL's backwards order of evaluation. we just don't notice it elsewhere because most other operations within lsl are communicative and quaternion math isn't.<br/>-- '''[[User:Void_Singer|Void]]''' <sup><small>([[User_talk:Void_Singer|talk]]|[[Special:Contributions/Void_Singer|contribs]])</small></sup> 11:09, 19 May 2009 (UTC)<br />
<br />
== Unjustified preference for Euler notation ==<br />
<br />
One thing that really annoys me with this page is that it seems to consider that the Euler coordinates are the easy way to deal with rotations, while the <x, y, z, s> quaternion representation is almost unintelligible.<br />
<br />
That's a common opinon, and as a matter of facts, most LSL scripts I have found use and overuse llEuler2Rot() and llRot2Euler().<br />
<br />
But that's simply wrong. Euler's notation is completly unintuitive for any non-trivial situation.<br />
<br />
To get convinced of it, try to figure out the Euler angles for the rotation of 45 degrees around XY diagonal (X = Y and Z = 0). Good luck ! :-).<br />
Now try figuring out the quaternions's values with the directing vector and sine and cosine of the half-angle: that's straightforward.<br />
<br />
I think this page is misleading a lot of new scripters into the wrong direction because of its preference for Euler angles. -- Catherine Pfeffer - 2008-08-28<br />
<br />
:I agree. '''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 14:19, 28 August 2008 (PDT)<br />
<br />
== Rotating Vectors ==<br />
<br />
The example:-<br />
<br />
//-- same as:<br />
llSetPrimitiveParams( [PRIM_POSITION, llGetPos() + (gPosOffset - gPosOffset * gRotArc) * llGetRot(),PRIM_ROTATION, gRotArc * llGetRot()] );<br />
<br />
gives no derivation of the variables gPosOffset and gRotArc.<br />
Which is less than useful to someone learning from the text.<br />
[[User:Gregory McLeod|Gregory McLeod]] 08:51, 1 September 2008 (PDT)<br />
:missed this comment before. although it should be guessable that offset = gPosOffset, and rot6x = gRotArc, I went ahead and made the section more explicit, and converted it to use lsl highlighting (so that all keywords would be linked) and removed a few slightly misleading viewer frame references. <br/>-- '''[[User:Void_Singer|Void]]''' <sup><small>([[User_talk:Void_Singer|talk]]|[[Special:Contributions/Void_Singer|contribs]])</small></sup> 11:00, 19 May 2009 (UTC)<br />
<br />
== Useful snippets ==<br />
<br />
The snippet we have now is kind of a string function. [http://www.isner.com/tutorials/quatSpells/quaternion_spells_12.htm How about converting these] from XSI to LSL? <br />
<br />
[http://lslwiki.net/lslwiki/wakka.php?wakka=LibraryRotationFunctions How about these] from lslwiki.net? ("All functions on this page are released into public domain and may have been based off other public domain works.")<br />
<br />
By the way, someone above complained about an unlinked reference to slerp() which seems to now be completely missing(!) Both of those have slerp(). [[User:Gia May|Gia May]] 07:15, 8 December 2008 (UTC)<br />
<br />
:I offer L$5000 to the first person who translates two functions from http://www.isner.com/tutorials/quatSpells/quaternion_spells_12.htm to the Useful snippets here, or for code constraining rotations to an arbitrary conic section. Runners up, if any, will be awarded on merit, and I am also asking the Lindens to help with this library deficiency bug bounty. IM me inworld for details. [[User:JS Uralia|JS Uralia]] 21:17, 2 February 2009 (UTC)<br />
::Hello, I went ahead and added three such functions: ConstrainQuaternion2Plane, ScaleQuaternion and CombineQuaternions (Slerp) though this last one already existed on the Wiki.--[[User:Jesrad Seraph|Jesrad Seraph]] 07:05, 17 May 2009 (UTC)<br />
<br />
Pending fulfillment of my promise to pay Jesrad L$5000 -- and [http://wiki.secondlife.com/w/index.php?title=Rotation&diff=220643&oldid=167253 Mephistopheles Thalheimer can attest I keep my word on these bounty payments] -- could someone please independently verify that this function works as it should?<br />
<br />
<lsl>// Constrain a rotation to a given plane, defined by its normal, this is very useful for vehicles that remain horizontal in turns:<br />
rotation ConstrainQuat2Plane(rotation source, vector normal)<br />
{<br />
return llAxisAngle2Rot(normal, <source.x, source.y, source.z> * normal * llRot2Angle(source));<br />
} // Jesrad Seraph</lsl><br />
<br />
I'm very troubled by the use of the first three elements of the quaternion in that manner, but in all honestly, I don't know enough to figure out what a correct answer is. [[User:JS Uralia|JS Uralia]] 20:43, 23 May 2009 (UTC)<br />
<br />
:I think it might just be correct. I can't verify it at the moment but the math looks to have the correct properties though the magnitudes of the vectors going into the dot product worry me. I'm wondering if <source.x, source.y, source.z> shouldn't be normalized first. On a side note, it doesn't handle the edge cases where source and normal haven't been normalized. -- '''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 09:56, 24 May 2009 (UTC)<br />
::More testing shows it is off by sometimes as much as 90 degrees... I will try to correct it, probably by normalizing the vector part first like suggested.--[[User:Jesrad Seraph|Jesrad Seraph]] 14:52, 7 July 2009 (UTC)<br />
<br />
== With regard to rotations of a child of an attachment ==<br />
<br />
I blow a raspberry at lsl. -- '''[[User:EddyFragment Robonaught|Eddy]]''' <sup><small>([[User talk:EddyFragment_Robonaught|talk]]|[[Special:Contributions/EddyFragment_Robonaught|contribs]])</small></sup> 06:37, 13 July 2009 (UTC)<br />
<br />
:Don't you just love {{Jira|SVC-93}}? Gage me with a spoon *rolls eyes*. -- '''[[User:Strife_Onizuka|Strife]]''' <sup><small>([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])</small></sup> 18:08, 13 July 2009 (UTC)<br />
<br />
Ah. Not just me then. I thought I just needed a degree in quantum maths to understand it. Thanx for the link. *voted* -- '''[[User:EddyFragment Robonaught|Eddy]]''' <sup><small>([[User talk:EddyFragment_Robonaught|talk]]|[[Special:Contributions/EddyFragment_Robonaught|contribs]])</small></sup> 01:41, 14 July 2009 (UTC)<br />
<br />
<br />
I think this is wrong: it claims that the llGetRot of a child prim of an attached object gives "global rotation of avatar * global rotation of prim (Not Useful)" This would be very useful if it were true and would let you calculate the rotation of the attachment. But I think llGetRot gives you the local rotation of the child prim * global rotation of the avatar, which is of no use that I can think of. I'm new at scripting so I'd appreciate some verification and so won't just change the page. [[User:Jonno Stromfield|Jonno Stromfield]] 11:04, 11 September 2009 (UTC)</div>Jonno Stromfield