0
\$\begingroup\$

I am using a Quaternion to represent the rotation of some object, and I would like to allow the user to rotate it about a single axis at a time using textbox, so he would write the angle that the object is rotated by (ex. at X-axis), then the object rotation is set to that rotation.
I know that, this operation q1 * q will rotate q by q1, but I don't know how to set the rotation at a single axis, Could any one help me to complete this function?

public void SetRotationX(float Angle)
{

}
\$\endgroup\$
1
\$\begingroup\$

Based on your function naming, I take it your just trying to set the rotation to a completely new rotation along that angle, as opposed to offsetting the rotation by a set amount.

In this case, rather than concatenating a quaternion to the current one, you can just create a new quaternion entirely. Note that you'll still probably want to pass in an x, y and z value to the function, relating to the other text boxes, or the current rotations along those angles.

Here are the outlines for the formulae to working out each axis of a quaternion, assuming no prior code is in place to create these Euler conversions already (note, pseudocode to avoid language issues):

void EulerAnglesToQuaternion( Quaternion q , double x , double y , double z )
{
    double cx = cos(x*0.5);
    double cy = cos(y*0.5);    
    double cz = cos(z*0.5);
    double sx = sin(x*0.5);
    double sy = sin(y*0.5);    
    double sz = sin(z*0.5);

    q.w = (cz*cx*cy)+(sz*sx*sy);
    q.x = (cz*sx*cy)-(sz*cx*sy);
    q.y = (cz*cx*sy)+(sz*sx*cy);
    q.z = (sz*cx*cy)-(cz*sx*sy);              
}
\$\endgroup\$
  • \$\begingroup\$ I will try this as soon as possible, thanks Joeb Rogers \$\endgroup\$ – O-BL Sep 18 '17 at 9:59
1
\$\begingroup\$

Going from the definition of quaternions as 3D rotations, we can represent a rotation about an arbitrary 3D axis by taking a unit vector in that direction, scaling it by the sine of half the angle of rotation, and using it as the 3 imaginary components of a quaternion. The remaining real component is then the cosine of half the angle, to keep the quaternion of unit length.

Quaternion AngleAxis(Vector3 axis, float angle) {

   Vector3 imaginary = axis.normalized * sin(angle/2f);

   Quaternion q;
   q.x = imaginary.x;
   q.y = imaginary.y;
   q.z = imaginary.z;

   q.w = cos(angle/2f);

   return q;
}

Rotating around just the x axis is then a simple special case:

Quaternion RotationAroundX(float angle) {

    // Equivalent to AngleAxis(new Vector3(1, 0, 0), angle)

    Quaternion q;
    q.x = sin(angle/2f);
    q.y = 0f;
    q.z = 0f;
    q.w = cos(angle/2f);

    return q;
}
\$\endgroup\$
  • \$\begingroup\$ Thanks DMGregory, when I am rotating around a single axis I have a pre-rotated object, so I cannot do it that simple. \$\endgroup\$ – O-BL Sep 18 '17 at 9:52
  • \$\begingroup\$ void RotationAroundX(Quaternion q, float Angle) {//implementation... } \$\endgroup\$ – O-BL Sep 18 '17 at 9:54
  • \$\begingroup\$ What about this case, where you have whatever rotation represented by quaternion and you want to set the rotation on a single axis? \$\endgroup\$ – O-BL Sep 18 '17 at 9:56
  • \$\begingroup\$ It sounds like you expect to be able to change just the "x part" of a rotation, independent of what's happened on the other axes, the way you might do by setting just one component of a translation vector while leaving the others untouched. Rotations don't work this way - their result is always dependent on the order in which the rotations are applied. So to pull out the "X part" of a quaternion, we need to know what other rotations were applied after X, or recompose the quaternion from the updated contributing rotations. \$\endgroup\$ – DMGregory Sep 18 '17 at 10:04
  • \$\begingroup\$ Could you provide a mathematical equations please? \$\endgroup\$ – O-BL Sep 18 '17 at 10:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.