Rotation is a complicated subject in 3D programming. Sometimes you need to rotate objects to a specific vector and hold them there. Sometimes you need to set them rotating around their axes. Neither of these tasks is intuitive in Second Life. Recently, I have learned how to rotate objects to a specific vector.
My lab in Shipley has two floors, but there is no gap for a staircase to get up to the second floor. To fix this problem I wrote a program to hide a section of the second floor and rez a staircase that I can climb to the upper floor. Then another program restores the hidden section and kills the staircase.
The function to rez some object (for instance a staircase) contained in some other object (just some random container) is llRezObject:
llRezObject(object_name, position, velocity, rotation, parameter);
The position must be relative to the position of the container (which can be accessed by llGetPos). After some experimentation I set the position of the rezzed staircase to llGetPos()+<2.0,0.0,3.0>. This placed the staircase exactly where I wanted it, but it was rotated to vector 0,0,0, whereas I wanted it rotated to vector 0,0,270.
Alas, setting the rotation in llRezObject to 0,0,270 did not work. Why not? The problem is that 0,0,270 is a Euler vector whereas Second Life requires rotations to be expressed in quaternions.

Roll, Pitch, and Yaw
The positional orientation 0,0,270 is called a Euler vector. The idea behind Euler vectors is to split the actual rotation into three simpler orientations. Rotation around these three orientations is called roll, pitch, and yaw. If I had direct access to the staircase parameters I could modify its orientation manually by entering 270 as its z-axis yaw. But you can only do that manually; you cannot do it with a program script. LSL (like other 3D programming languages) requires that rotations be expressed in quaternions instead of Euler vectors.
A quaternion has four values, 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. Not understanding the math at all, I nevertheless think the fourth value is a factor in accordance with which the other three values are altered during a bank.
Anyway, quaternions are useful in graphics simulations for their ability to accurately express rotations around 3-axes. As I mentioned, LSL scripting requires that Euler vectors be expressed in quaternions. Luckily, there are standard functions for this. Three lines of code are required:
1. vector eul = <0,0,270>;
This is the rotation I want in Euler notation: 270 degrees around the z-axis. So I set that vector to the variable eul. eul now expresses an angle in degrees.an>
2. eul *= DEG_TO_RAD;
Next, degrees are converted to radians. The radian is a unit of angular measure, equal to 180/π degrees, or about 57.2958 degrees. This second line assigns the value (eul * 0.01745329238) to the variable eul. Now we have eul as an angle expressed in radians.
3. rotation quat = llEuler2Rot(eul);
This function llEuler2Rot assigns quat the value of eul converted to a quaternion. Voila! quat is the rotation I need. So I plug quat into the little program below, which rezzes the staircase in the proper position and rotates it 270 degrees around the z axis.
default
{
state_entry() {
llListen(0,””, NULL_KEY, “”);
}
listen(integer channel, string name, key id, string message) {
if (message == “rez_staircase”)
{
vector eul = <0,0,270>
eul *= DEG_TO_RAD;
rotation quat = llEuler2Rot(eul);
llRezObject(llGetInventoryName(INVENTORY_OBJECT,0), llGetPos()+<2,0,3>,ZERO_VECTOR,quat,0);
}
}
}
Merry Christmas!