You are currently not logged in! Enter your authentication credentials below to log in. You need to have cookies enabled to log in.
IMPORTANT:
Please note that this is NOT an introductory text on rotations, but a reference on the usage of the rotation type in LSL. If you want to learn on rotations, you may want to check the Rotations tutorial.
Unlike many other languages, LSL has native support for several operations that are common in 3D geometry. The rotation or quaternion type is fundamental to that support. At the lowest level, a rotation can be defined as a type that is able to hold four floats, but LSL supports many operations that are designed for geometry handling. quaternion is an alias for rotation; they can be used indistinctly.
A rotation literal is written as four comma-separated float expressions enclosed in angle brackets. As usual, integer expressions are automatically cast to float. Note, however, that it's unusual to write a rotation literal yourself; more commonly, rotation values come from the result of functions such as llGetRot
, llEuler2Rot
, llList2Rot
, etc. While functions that accept rotation values are somewhat permissive, writing a valid rotation (one which when applied to a vector, returns a vector of the same length) is not a trivial task and you're not recommended to do it unless you have a good understanding of the underlying rules.
In particular, <0, 0, 0, 0>
is not a valid rotation. It can work in some situations but will utterly fail in others. The null rotation (a rotation that doesn't alter the original object's orientation) is written as <0, 0, 0, 1>
and has the associated constant ZERO_ROTATION.
As with vectors, the components of a quaternion can only be accessed individually when they are in a variable, and in that case, the syntax is the name of the variable followed by a dot and then the letter x, y, z or s (the components of a literal appear in that order). For example, rotation_var.s
is the fourth (s) component of a quaternion.
These are operations that are very rarely used, and only in cases where the maths require it, which in LSL is pretty close to never. However, they are implemented, so here's a description:
-r
is the same as <-r.x, -r.y, -r.z, -r.s>
. It turns out that for quaternions (in the mathematical sense) that represent rotations (in the sense of an orientation in space), r and -r represent the same rotation, therefore this operation is of little use besides some hard maths.q+r
gives the same result as <q.x + r.x, q.y + r.y, q.z + r.z, q.s + r.s>
, and similarly for subtraction. Note, however, that this is not how you accumulate rotations: you do that by multiplying them (see below). In most cases, the addition of rotations gives something that is not a valid rotation, so better don't use it unless you know the underlying maths.
There are two operations with rotations that use the *
multiplication operator: vector*
rotation and rotation*
rotation. No other combination of rotation with any other type or in any other order is supported. In particular, the following are NOT supported: rotation*
vector, float*
rotation and rotation*
float.
vector*
rotation returns a vector, and is the result of applying the rotation to the vector. The rotation needs to be valid (in mathematical terms, normalized), otherwise the vector's length will also be altered. All LSL functions except llAxes2Rot
and llList2Rot
always return normalized rotations, (llAxes2Rot does too if it receives proper arguments).
rotation*
rotation has the effect of accumulating the rotations. Say you have an object and rotate it by q and then by r; the final orientation will be the same as if you rotated it by the single rotation given by q*r
.
For example, if q is a rotation that turns 40° counter-clockwise over the positive Z axis, and r is a rotation that turns 30° clockwise over the positive Z axis, then q*r
will represent a rotation that turns 10° counter-clockwise over the positive Z axis.
Note that due to how the concept of rotating an object works, q*r
is not always the same as r*q
. This may seem unintuitive, but rotations work like that in the real world too. In the example given above it would be the same, as the rotations turn over the same axis, but in general it's not the case.
Rotations can be divided by another rotation, and vectors can be divided by a rotation. In both cases, the effect is the same as multiplying by the rotation that would cancel the one in the denominator.
For example, if q is a rotation that turns 40° counter-clockwise over the positive Z axis, and r is a rotation that turns 30° clockwise over the positive Z axis, then q/r
is a rotation that turns 70° over the positive Z axis (because the rotation that cancels r is one that turns 30° counter-clockwise, and multiplying q by that one gives a total rotation angle of 70°).
The rotation that cancels a given rotation can be obtained by negating the s component. Unfortunately, LSL does not support an operator that does this, so it has to be done by hand. For example: <q.x, q.y, q.z, -q.s>
is the inverse rotation of q, or if you want to invert the variable you can do: q.s = -q.s;
As with vectors, type cast of a rotation is very limited:
(rotation)rotation_value
does nothing special to the value, as expected.(rotation)string_value
is supported; see Type casting of strings for details.(string)rotation_value
is supported too; see Type casting a float to string for details.(list)rotation_value
results in a list with one single element of type rotation.
If v = vxi+vyj+vzk is a vector and r = rw+rxi+ryj+rzk is a quaternion, then v*r
does the operation r·v·r* (where r* is the conjugate of r), so if the quaternion is normalized, it performs a conjugation of v by r, which has the effect of rotating the vector (see http://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation). As expected, if the quaternion isn't normalized, it will scale the vector as well.
q*r
(for two quaternions q and r) performs the multiplication in inverse order with respect to the maths convention, i.e. it performs r·q.