I have a quaternion that represents my camera direction. Using this, I can update the camera’s position and calculate the look-at coordinates and up vector. All this works great and I’ve got a nice demo of flying around in a 3D scene with control of heading, pitch and roll of the camera.

Now, I want to place an object directly in front of the camera and keep its position and orientation locked in sync with the camera’s. That is - it should just appear fixed in front of the camera.

Using the camera’s direction quaternion, I can correctly position the object, but I can’t figure out how to calculate the Euler angles that I need to pass to glRotate in order to orient the object.

I’ve tried numerous examples from euclidianspace.com, including the quaterion-to-euler conversion, but nothing is working. Depending on which direction I’m flying the object twists around in the wrong ways flips upside down or backwards. I really tried to do my homework before posting - I’ve read and tried dozens of different approaches, but I think I’m probably missing something fundamental.

Even if there is some other way to orient the object, I really would like to be able to determine the Euler angles from the camera direction for other uses in the program.

Here is the quaternion-to-euler code. I keep coming back to this because it seems like it should be what I’m looking for:

public static Number3d toEuler(Quaternion q)

{

float test = q.x*q.y + q.z*q.w;

// handle singularities

if (test > 0.4999f)

return new Number3d(

2f*(float)Math.atan2(q.x,q.w)*r2d,
(float)Math.PI/2*r2d,

0f);

if (test < -0.4999f)

return new Number3d(

-2f*(float)Math.atan2(q.x,q.w)

*r2d,*

(float)-Math.PI/2r2d,

(float)-Math.PI/2

0f);

float sqw = q.w

*q.w;*

float sqx = q.xq.x;

float sqx = q.x

float sqy = q.y

*q.y;*

float sqz = q.zq.z;

float sqz = q.z

return new Number3d(

(float)Math.atan2(2

*q.y*q.w-2

*q.x*q.z , sqx - sqy - sqz + sqw)

*r2d,*

(float)Math.asin(2test)

(float)Math.asin(2

*r2d,*

(float)Math.atan2(2q.x

(float)Math.atan2(2

*q.w-2*q.y*q.z , -sqx + sqy - sqz + sqw)*r2d);

}