Thomas Aylesworth

I've read a couple of very helpful threads here on Quaternions, so I decided to try putting them to use. I was able to use them to move a 3D object around using a modification of Riemer's flight simulator tutorial, to which I added a second object.

However, I then tried to initialize the orientation of the two objects to point towards each other from any given starting location, and that didn't work the way I expected. Can someone help me understand what's wrong with the following code

 public void SetOrientation(Vector3 startLocation, Vector3 targetLocation){ Matrix target = Matrix.CreateLookAt(startLocation, targetLocation, Vector3.Up); Orientation = Quaternion.CreateFromRotationMatrix(target);} public virtual void Update(GameTime time){ float distance = time.ElapsedGameTime.Milliseconds * Speed; Vector3 move = Vector3.Forward; move = Vector3.Transform(move , Matrix.CreateFromQuaternion(Orientation)); move .Normalize(); Position += move * distance;}

I'm calling GetOrientation with a start location of (-3, 3, 0) and a target of (3, -3, 0). I expected the Update call would then move the object towards the target. Instead, the object moves along the X axis -- its X value continues to decrease while Y and Z remain the same.

Any help is much appreciated!

Tom

### Re: XNA Framework Help Using Quaternion To Find Target

Kyle_W

Well, I could be wrong, but these are my thoughts:

First, I suspect it may not be valid to create a Quaternion from your target matrix because the target matrix is a transformation matrix and not simply a rotation matrix.

Second, if I understand your code correctly, you want the move vector to represent the direction to move. I believe you can correctly and more easily calculate the move vector as follows:

Vector3 move = targetLocation - startLocation;

move.Normalize();

### Re: XNA Framework Help Using Quaternion To Find Target

thomas.aylesworth

Ah, thank you. I was so focused on it being a problem with my lack of understanding of quaternions that I didn't consider that I was misusing the matrix. Whoops.

The reason I'm not using a vector to represent my direction of movement is that this is a flight simulation where the user can rotate the movement around all three axes. I'm basically just playing with what I learned from the quaternion tutorial thread here, since I'd never heard of quaternions before then. I wanted to be able to set the initial orientation of both objects to have them point towards each other. And, thanks to you, it now works.

Here's the final code if anyone else is trying to do this. Note that it assumes the two objects are in the same plane, but can easily be extended to compute the rotation angles around the other two planes if desired.

 public void SetOrientation(Vector3 startLocation, Vector3 targetLocation){ float targetAngle = GetTargetAngle( new Vector2(startLocation.X, startLocation.Y), new Vector2(targetLocation.X, targetLocation.Y)); Orientation = Quaternion.CreateFromAxisAngle(Vector3.Right, MathHelper.PiOver2 * 3) * Quaternion.CreateFromAxisAngle(Vector3.Up, targetAngle);} private float GetTargetAngle(Vector2 location, Vector2 target){ Vector2 delta = target - location; return (float)Math.Atan2(delta.Y, delta.X);}

### Re: XNA Framework Help Using Quaternion To Find Target

Kyle_W

Well, I'm glad you got it working, but I'm confused by your statement that you are not using a vector because it's a flight simulator with rotation in all 3 dimensions. The targetLocation - startLocation formula works for determining the directional vector between two points in 3D as well as 2D. Once you have this initial directional vector, you can rotate the vector using matrices or quaternions as needed.

### Re: XNA Framework Help Using Quaternion To Find Target

thomas.aylesworth Kyle_W wrote:
 Well, I'm glad you got it working, but I'm confused by your statement that you are not using a vector because it's a flight simulator with rotation in all 3 dimensions. The targetLocation - startLocation formula works for determining the directional vector between two points in 3D as well as 2D. Once you have this initial directional vector, you can rotate the vector using matrices or quaternions as needed.

I thought you were suggesting replacing the code listed above in my Update method by removing the quaternion. Are you instead saying I could simplify setting the original orientation (rotation) by using a directional vector I understand that the directional vector can be computed in 3D by simply subtracting the two Vector3D positions. But I don't know how to then get the quaternion representing the rotation out of that.

Or maybe I'm completely misunderstanding what you mean! It wouldn't be the first time I was confused... ### Re: XNA Framework Help Using Quaternion To Find Target

Kyle_W

Yes, the initial direction is most easily calculated by vector subtraction. Initially you stated you only wanted the objects to move toward each other. I just wanted to make it clear that vector subtraction will give you the proper direction whether you are working with 2D or 3D. You agreed, so I'm glad we cleared that up. Yes, if you need a rotation around that vector, use Quaternion.CreateFromAxisAngle().

### Re: XNA Framework Help Using Quaternion To Find Target

Mike36

I've been struggling to get this to work on more than one rotation plane. Good news is I found this thread:

http://forums.microsoft.com/MSDN/ShowPost.aspx PostID=1224639&SiteID=1

It explains how to use Matrix.CreateLookAt to create the rotation matrix. The bad news for me is I've yet to figure out how to point one object at another, but keep the rotation at a constant rate. Actually, what I have is a rotation rate that speeds up to maximum, then slows down to nothing. I can rotate an object by a specific amount (say, 90 degrees to the right) but the hard part has been to compute the angles to rotate by. Part of the problem stems from when the target is directly in front, to the side, above, or below the object that will rotate. Here's what I do to rotate a set amount:

/// <summary>

/// Performs an auto rotate and checks to see if the auto rotate finished.

/// </summary>

/// <returns>True if auto rotate completed, false if not.</returns>

protected virtual bool autoRotateDone()

{

float TimeUpdates = m_fRotationsPerUpdate / m_fRotPerUpdAccel;

//If our current angle is < our target angle, then keep rotating

if (m_fCurAngle < m_fTargetAngle)

{

//If our current angle + the angle we'd travel while stopping is < the target angle,

//then keep rotating.

if (m_fCurAngle + AngTravStopping < m_fTargetAngle)

{

//Increase our rotation speed.

rotateToFull();

}

//Slow down or we'll overshoot our target angle

else

{

//Slow down

rotateToStop();

}

//Update the angle and let caller know we're not done yet.

m_fCurAngle += m_fRotationsPerUpdate;

if (m_fRotationsPerUpdate != 0f)

return false;

}

//Ok, we're done with auto rotate.

m_quatCurOrientation = m_quatNewOrientation;

m_fRotationsPerUpdate = 0f;

m_fCurAngle = 0f;

m_fTargetAngle = 0f;

m_RotationType = RotationTypes.None;

return true;

}

### Re: XNA Framework Help Using Quaternion To Find Target

Mike36

By the way, I've found the Quaternion.Slerp method, but I cannot figure out how to slow it down so that, if an object rotates at most 60 degrees per second, the Slerp method would take 4 seconds to complete if the ship had to rotate about 240 degrees.

### Re: XNA Framework Help Using Quaternion To Find Target

Kyle_W

With regard to your question, I'm still not completely clear what you are trying to do. If you want to animate from one quaternion orientation to another quaternion orientation at a steady rate of 60 degrees per second, then you need to know the angle between the axis vectors of the two quaternions. There are many docs on the web about doing this. Here is one:

http://www.euclideanspace.com/maths/algebra/vectors/angleBetween/index.htm

To be clear, I'm talking about the angle between the axes of the quaternions, not the angle of rotation around each quaternion axis. Once you know the angle between the axes, then you know that this angle is equivalent to the zero-to-one range of the amount parameter in the Slerp() method. You can then use the GameTime object of your game's Update() method to find the fraction of a second that has passed since the last frame and multiply that fraction times 60 to determine what fraction of 60 degrees this frame should represent. Then you divide that fractional angle by the angle between the quaternion axes, and this would give you the value to add to the amount parameter of the Slerp() method.