XNA Quaternions Sample Program: This program makes use of Quaternions for the rotation of points/vectors around an arbitrary axis in 3D space. In particular, we use Quaternions to create a first-person camera system that is used to navigate a player through a 3D world. 1. Creating the world: Start off by creating a flat, two dimensional plane to represent the ground level in the scene. The plane can be represented with two triangles using either a triangle list or triangle strip primitive topology. The plane should be tiled with a texture image that resembles some sort of floor/ground surface. o Note: texture coordinates that exceed 1.0 in either the U or V dimensions will produce a tiling effect. 2. Creating the player: Conceptually our world can be thought of as two dimensional (in the XZ plane). Likewise, the player can be thought of as a point on the XZ plane that is moving along the ground created in part 1. Define the following three attributes of the player in your program: i. ii. iii. Position Height Speed The position is essentially a 3d point in space where the player’s feet would come into contact with the world. The height is a scalar that defines how high the camera should be positioned away from the player’s position on the Y axis in the world’s coordinate system. Lastly, the speed is another scalar that defines the distance travelled by the player in some length of time. 3. Creating the camera: A first-person camera can be represented as a three dimensional coordinate system, with the camera positioned at the origin: Store these three vectors in your program and give them some initial values such as: o LookDir = (0, 0, -1) o RightDir = (1, 0, 0) o UpDir = (0, 1, 0) Using quaternions we can now apply rotations to the camera using the three basis vectors (look, up, right) based on user input. First, read in the change in the horizontal position of the mouse cursor and use it to generate a turning angle (yaw) for the frame. Next, read in the change in the vertical position of the mouse cursor and use it to generate a tilting angle (pitch) for the frame. Use these two angles to rotate the orientation of the three camera vectors. Note that a yaw is a rotation around the up vector, and a pitch is a rotation around the right vector. Typically in first-person games the yaw rotation is around the world’s up vector as opposed to the camera’s current up vector. If the camera was allowed to “fly” through space (perhaps as a spectator), then it would make sense for the yaw rotation to use the camera’s up vector. o As an example, if a tilt (pitch) rotation is being performed we would need to rotate both the look direction and the up direction by some angle around the camera’s right vector. In this case, the angle would be read from the vertical mouse movements. o To create a quaternion that represents a rotation around a particular axis you can use the function contained within the Quaternion data structure: quaternion = Quaternion.CreateFromAxisAngle(Vector3 axis, float angle) o To rotate a vector around a quaternion you can use the function contained within the Vector3 data structure: newVector = Vector3.Transform( Vector3 vector, Quaternion rotation) After both rotations (yaw and pitch) have been applied on the camera’s basis vectors, you will need to rebuild the view matrix in your program. o NOTE: The look, up, and right vectors of the camera should all be normalized and orthogonal to each other. o To orthogonalize a set of three 3D vectors (lookDir, upDir, rightDir): i) lookDir = lookDir.normalize(); ii) rightDir = Cross( lookDir, upDir ).normalize(); iii) upDir = Cross(rightDir, lookDir); 4. Controlling the Player: In your input handling function, calculate a normalized 2D movement vector (in the XZ-axis) based on the user’s keyboard input. The player should be able to move forwards and backwards (relative to the direction the camera is looking), as well as strafe to the left and to the right (relative to the camera’s current right vector). o Note: We do not want to move the player at all in the Y-axis assuming the ground you are using is flat. Therefore if the player is looking up or down in the world’s up direction, this should not affect the movement direction. If you choose to have a 3D landscape rather than a flat plane, you would want to move the player in the direction tangent to the terrain’s surface. Multiplying this normalized movement vector by the player’s speed will give the velocity vector of the player in a particular frame. Use this velocity to displace the player’s current position. Add the ability for the player to crouch and crawl. This can be achieved by modifying the player’s height value. The best approach would be to store a floating point scalar in the range [0, 1] and multiply the player’s height by this value when setting the camera’s position for the frame. Using a similar approach as mentioned above, modify the player’s speed value depending on the current stance they are in. If the player is standing, the speed should be 100%. If the player is crouching, the speed should be approximately 50%. And lastly, if the player is crawling, the speed should be roughly 10%. 5. Additional Features: In this program we implemented a yaw and pitch rotation system using quaternions. We could also add the ability to “roll” the camera by performing rotations around the camera’s current look vector. This rotation can give the effect of leaning, however, we also would need to rotate the camera’s position around a particular point on the player (such as the neck or waist) to get the full effect. To get a better understanding of the current state of the camera’s view space, render the camera’s look, up, and right vectors (as line list primitives) each frame as a HUD element. o One simple way to render a 3D object as a HUD element is to add a translation matrix to the projection matrix. Once objects are in projection space they have “Normalized Device Coordinates” meaning that the vertices are in the range [-1, 1] in the XY-axis (where -1 and 1 are the edges of the screen/back buffer).