Rotating an object about local angles/axes
The functions SetAngle and Rotate rotate objects about the world axes. In order to apply local rotations, the angles need to be derived first. It is possible to rotate an object about local angles by first specifying the local angles, then extracting the world angles from the local rotation and applying those to the object.
Any local rotation is dependent on the order in which the individual rotations are applied. This is true because the local axes are dependent on each other.
Because of this, it is important to specify the axis order prior to calculating the world rotation.
An axis order of XYZ means that the X rotation is applied first, then the Y and lastly the Z rotation.
These declarations are needed:
;the object one wishes to rotate ref myObject ;specifes order of rotations. float axisOrder ;1 = xyz ;2 = xzy ;3 = yxz ;4 = yzx ;5 = zxy ;6 = zyx ;the local angles float localAngX float localAngY float localAngZ ;the world angles float worldAngX float worldAngY float worldAngZ ;sine and cosine of local x, y, z angles float sx float cx float sy float cy float sz float cz ;the cells of the rotation matrix float r11 float r12 float r13 float r21 float r22 float r23 float r31 float r32 float r33
The actual rotation code:
set axisOrder to 3
set sx to sin localAngX set cx to cos localAngX set sy to sin localAngY set cy to cos localAngY set sz to sin localAngZ set cz to cos localAngZ ;creation of rotation matrix in axis order if (axisOrder == 1) ;XYZ set r11 to ( cy * cz) set r12 to ( cy * -sz) set r13 to ( sy ) set r21 to ( sx * sy * cz + cx * sz) set r22 to ( sx * sy * -sz + cx * cz) set r23 to (-sx * cy) set r31 to ( cx * -sy * cz + sx * sz) set r32 to ( cx * sy * sz + sx * cz) set r33 to ( cx * cy) elseif (axisOrder == 2) ;XZY set r11 to ( cz * cy) set r12 to ( -sz ) set r13 to ( cz * sy) set r21 to ( cx * sz * cy + cx * cz) set r22 to ( cx * cz) set r23 to ( cx * sz * sy + -sx * cy) set r31 to ( sx * sz * cy + cx * -sy) set r32 to ( sx * cz) set r33 to ( sx * sz * sy + cx * cy) elseif (axisOrder == 3) ;YXZ set r11 to ( cy * cz + sy * sx * sz) set r12 to ( cy * -sz + sy * sx * cz) set r13 to ( sy * cx) set r21 to ( cx * sz) set r22 to ( cx * cz) set r23 to ( -sx ) set r31 to (-sy * cz + cy * sx * sz) set r32 to ( sy * sz + cy * sx * cz) set r33 to ( cy * cx) elseif (axisOrder == 4) ;YZX set r11 to ( cy * cz) set r12 to ( cy * -sz * cx + sy * sx) set r13 to ( cy * -sz * -sx + sy * cx) set r21 to ( sz ) set r22 to ( cz * cx) set r23 to ( cz * -sx) set r31 to (-sy * cz) set r32 to ( sy * sz * cx + cy * sx) set r33 to ( sy * sz * -sx + cy * cx) elseif (axisOrder == 5) ;ZXY set r11 to ( cz * cy + sz * sx * -sy) set r12 to (-sz * cx) set r13 to ( cz * sy + sz * sx * cy) set r21 to ( sz * cy + cz * sx * sy) set r22 to ( cz * cx) set r23 to ( sz * sy + cz * -sx * cy) set r31 to ( cx * -sy) set r32 to ( sx ) set r33 to ( cx * cy) else ;ZYX set r11 to ( cz * cy) set r12 to (-sz * cx + cz * sy * sx) set r13 to ( sz * sx + cz * sy * cx) set r21 to ( sz * cy) set r22 to ( cz * cx + sz * sy * sx) set r23 to ( cz * -sx + sz * sy * cx) set r31 to ( -sy ) set r32 to ( cy * sx) set r33 to ( cy * cx) endif ;Extraction of worldangles from rotation matrix if (r13 > 0.9998) ;positive gimbal lock set worldAngX to -ATan2 r32 r22 set worldAngY to -90 set worldAngZ to 0 elseif (r13 < -0.9998) ;negative gimbal lock set worldAngX to -ATan2 r32 r22 set worldAngY to 90 set worldAngZ to 0 else ;no gimbal lock set r23 to -r23 set r12 to -r12 set worldAngX to -ATan2 r23 r33 set worldAngY to -ASin r13 set worldAngZ to -ATan2 r12 r11 endif ;apply extracted rotation myObject.setAngle x worldAngX myObject.setAngle y worldAngY myObject.setAngle z worldAngZ
Special Note
This code has been tested ingame and works reliably well. It is advided to pay special attention to the axis order.
Notes
- Some types of object, specifically Actors, do not allow for rotation about all three axes. Other objects, such as activators have all three degrees of freedom.
- Gimbal Lock is accounted for. Whenever two of the axes are orthogonal, becoming arbitrary, two of the axes (y and z) are reset to a more preferable orientation.
- For a more in-depth discussion of the math behind this, see wikipedia.org and euclideanspace.com.