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!