Euler angles to quaternion: Is this correct?

Quick question:

I have the Euler angles (defined as rotX, rotY, rotZ in radians) and I’m trying to convert these to a quaternion. Now, my understanding of quaternions is extremely limited, but I’m wondering if the following code is working:


    public void setOrientation(float x, float y, float z){
		x*=0.5f;
		y*=0.5f;
		z*=0.5f;
		
		float c1 = (float)Math.cos(x);
		float c2 = (float)Math.cos(y);
		float c3 = (float)Math.cos(z);
		
		float s1 = (float)Math.sin(x);
		float s2 = (float)Math.sin(y);
		float s3 = (float)Math.sin(z);
		
		localOrientation = new Quaternion(
				s1*s2*c3 + c1*c2*s3,
				s1*c2*c3 + c1*s2*s3,
				c1*s2*c3 - s1*c2*s3,
				c1*c2*c3 - s1*s2*s3
		);
	}

Input:


1.570796 0.000000 0.000000

Output:

0.0 0.70710665 0.0 0.7071069

From what I can see, the direction seems to be off, assuming bones aren’t supposed to extrude in a 90 degree angle out of the body. =S

I’m not really sure about what you are trying to archive and I’m not a pro at Quaternion math at all, but I tried to do some googleing and searching in Stackoverflow.

I’ve found this and I found very much similarities between your code and the one on the site. But I’m not pretty sure what you want to do with this [icode]x = (float) Math.PI/2;[/icode]… Is it supposed to be there? As well as the *= 0.5f; operations?
I guess they are… I’ve got no idea about what you are doing anyways, but I hope the site I’ve linked helps you :slight_smile:

Ah, dammit, that was a remnant of a test. Someone mentioned that you sometimes had to add PI/2 to the x rotation. That line used to be x += (float)Math.PI/2…

That was the site I used to write that code. If you look at it, you’ll see that they all need the rotation angles divided by 2, so I just did that once in the beginning.

Anyway, I think I got it working correctly, at least for this simple conversion. I just switched around the coordinates so it became like this:


      float c1 = (float)Math.cos(z);
      float c2 = (float)Math.cos(y);
      float c3 = (float)Math.cos(x);
      
      float s1 = (float)Math.sin(z);
      float s2 = (float)Math.sin(y);
      float s3 = (float)Math.sin(x);

Still not sure if it’s really correct though…

No time to look through this atm, but it should be: {sin(t/2)u, cos(t)} where t is the angle of orientation and ‘u’ is the unit axis of rotation.

Oh yes… I just further searched wikipedia::

Seems like
[x] Heading = z rotation
[x] Elevation = y rotation
[x] Bank = x rotation

Yup! Though I have to say that naming the axes like that makes no sense what so ever.

On a slightly unrelated note, now I just need to figure out what this means:

[quote]X is north in SMD. Elsewhere in Source it is east.
[/quote]
X is NORTH?!

Mapping the position and normal coordinates like this produces the right result but is it really correct?


	public void setPosition(float x, float y, float z){
		this.x = x;
		this.y = z;
		this.z = -y;
	}

This should work:


 public static Quaternion4f eulerToQuaternion( float eulerX, float eulerY, float eulerZ )
    {
        double sx = Math.sin( eulerX / 2 );
        double sy = Math.sin( eulerY / 2 );
        double sz = Math.sin( eulerZ / 2 );
        double cx = Math.cos( eulerX / 2 );
        double cy = Math.cos( eulerY / 2 );
        double cz = Math.cos( eulerZ / 2 );
        double cycz = cy * cz;
        double sysz = sy * sz;
        double d = cycz * cx - sysz * sx;
        double a = cycz * sx + sysz * cx;
        double b = sy * cz * cx + cy * sz * sx;
        double c = cy * sz * cx - sy * cz * sx;

        Quaternion4f q = new Quaternion4f( ( float ) a, ( float ) b, ( float ) c, ( float ) d );
        q.normalize();

        return ( q );
    }

The end result depends on the conventions…how the pre-defined euler angles match yours. right vs left handed & how they point within each. What I’m going to assume you’re asking is: local coordinate frame changes of x followed by y followed by z. Quaternion perspective: rotation of ‘a’ radians about unit axis in direction ‘u’ = (sin[a/2]u, cos[a/2]), so:
R<sub>0</sub> = (sin[x/2](1,0,0), cos[x/2]) = ((sx,0,0),cx) R<sub>1</sub> = (sin[y/2](0,1,0), cos[y/2]) = ((0,sy,0),cy) R<sub>2</sub> = (sin[z/2)(0,0,1), cos[z/2]) = ((0,0,sz),cz)
If right handed coordinate frames, then the product of quaternions A & B (AB) can be considered a global rotation of B with respect to A…OR a local rotation of A with respect to B. So since Euler angles are local rotations:

R<sub>0</sub>R<sub>1</sub>R<sub>2</sub> = ((cy cz sx + cx sy sz, cx cz sy - cy sx sz, cz sx sy + cx cy sz), cx cy cz - sx sy sz)

If you change to left-handed, then the notions of global & local flip:

R<sub>2</sub>R<sub>1</sub>R<sub>0</sub> = ((cy cz sx - cx sy sz, cx cz sy + cy sx sz, cx cy sz - cz sx sy), cx cy cz + sx sy sz)

Notice that neither of these match Stranger’s code, as there is a different ordering occurring…there are combinatorial number of ways to define Euler-angles and ya gotta know which it is.