Sunteți pe pagina 1din 6

Understanding Quaternions in Unity 3D

A tutorial which helps get your head from Eular Angles to Quaternions

By David Lancaster

Introduction
Hey Guys!

This is a tutorial for beginners to Unity, who either have no idea what a Quaternion is and how to use it, or are
struggling trying to get their brain from Eular Angles to Quaternions. Although this tutorial is a great introduction,
there are many intelligent forum users and threads that can provide much more valuable information than you
may find here. Regardless I hope this tutorial helps!

There are many ways to go about coding rotations, I have limited experience so there may be more efficient
ways to code than I have here. I am going to assume that you know some basic things about Unity's scripting
language. The transform object and the various properties and functions it can use.

If you are new to scripting then it is very normal for information found in this tutorial to go over your head, just
remember, it's okay, you're not the only one who experiences it. If something doesn't make sense keep going
through the tutorial, post a thread on the forums asking for help, reread certain sections of the tutorial. And even
after you spend a lot of time trying to understand something and you still don't, it's okay, it happens to most of
us.

What are Quaternions?


Unity 3D separates rotations from vectors by using a different type of variable. Quaternions are used to process
and deal with rotations, whilst Vectors are used for positions and directions. From your side of things there isn't
too much difference between the two, however Quaternions are much faster for the CPU to process and thus
Unity objects are built with their rotation value being a Quaternion type.

If you are used to using Vectors and Eular Angles, converting and using them to rotate an object in Unity can be
confusing at first. Especially if you are not aware how you can go about rotating vectors and converting vectors
to Quaternions.

There are many functions which link Vectors, Eular Angles and Quaternions to each other. The two types of
classes that we'll use shall be 'Quaternion' and 'Vector3'. Each contains functions to work with each other. Also,
the Transform object contains it's own set of good features you can use to help with rotations..

Why C Sharp?
Unfortunately I am much more familiar with C Sharp than I am with Java, I have found C Sharp to require more
syntax, however I do find it's structure more organized than Java. I shall attempt to explain the C Sharp syntax
throughout this tutorial as we come across it.

Let's start with a tutorial.


Tutorial - creating a camera to orbit an object
Start by creating a new blank unity project. We shall begin by making a gameObject, say a cube, and create a
camera which looks at the cube and can rotate around the cube using the arrow keys.

I have begun by creating a plane in the 'GameObject – Create Other' menu, named it Ground and scaled it's X
and Z components by 10. I also created a material in the project window by right clicking in the project window
and selecting 'create – material', I made the material a dark color and assigned the material to the Ground's
mesh renderer material. I then created a cube and named it Player, the reason I added this material to the
ground is so that the player isn't the same color as the ground.

(to rename an object in Unity, select it first, then click it and leave your mouse over it for a second or two, you
should then be able to rename the object)

Next we are going to create a new C Sharp script and name it 'PlayerScript' (right click in the project window).
Open up your script and change the classes name to the name of the script (this is very important and wont work
unless you do this):

using UnityEngine;
using System.Collections;

public class PlayerScript : MonoBehaviour {

// Use this for initialization


void Start () {
}

// Update is called once per frame


void Update () {

}
}

Now let's drag the script onto our player object in game.

The next step is to be able to access the camera from script, there are many ways to go about doing this
however for this tutorial we'll create a public variable GameObject, and we shall attach the camera to it.

Change your script as follows:

public class PlayerScript : MonoBehaviour {

public GameObject cameraObject;

// Use this for initialization


void Start () {

A difference between C Sharp and Java is that when defining variables a type must be giving, in this case our
type is GameObject and the variable/pointer is named cameraObject. Let's go to our Unity window and drag our
MainCamera object (which should have automatically been created when you started a new unity project) onto
the cameraObject field which appears in the PlayerScript component of the Player object.

In C Sharp, all public variables declared inside the class, can be accessed and changed by external scripts, if
those other scripts have a pointer to this particular GameObject you can access it's attached script component
and the public variables within it. For example, any variables declared private, can only be accessed and
changed within that script. Anything declared public can be accessed from other scripts that you write in your
game. Anything declared public shall also appear in the script component in the Object's inspector window, as
we have seen with the variable cameraObject.
Here's where the bulk of our code comes in, it may seem overwhelming if you're new to this, don't worry I'm
going to explain the code in detail, go ahead and copy paste the code, don't run your game just yet, we want to
set some variables too:

public class PlayerScript : MonoBehaviour {


public GameObject cameraObject;

public float cameraDistance; // the distance the camera should be placed from the player
public float cameraHeight; // how high the camera should be
private float cameraAngleToPlayer; // the current angle the camera is to the player
private Vector3 tempVector; // a temporary vector we shall use for calcuations

// Use this for initialization


void Start () {

// Update is called once per frame


void Update ()
{
tempVector = Vector3.forward;
if ( Input.GetKey("left") ) // rotation the angle based on input
{
cameraAngleToPlayer = cameraAngleToPlayer - (Time.deltaTime * 50f);
} else if ( Input.GetKey("right") ) {
cameraAngleToPlayer = cameraAngleToPlayer + (Time.deltaTime * 50f);
}
tempVector = Quaternion.AngleAxis(cameraAngleToPlayer, Vector3.up) *
tempVector; // we are now rotating the Vector around the vertical (y) axis by an angle specificed in the variable
'cameraAngleToPlayer'
cameraObject.transform.position = transform.position + (tempVector.normalized *
cameraDistance) + new Vector3(0,cameraHeight,0);
cameraObject.transform.rotation = Quaternion.LookRotation(transform.position -
cameraObject.transform.position);
}
}

Firstly we have defined some new variables, cameraDistance is how far the camera will be placed from the
player, I have set it's value to 10 in my editor. Camera Height is how high to place the camera from the player,
set it to about 5. As these are public variables we can change them from the edtior. Our private variables, we
could have defined locally within the Update function however I choose to define them above. Go ahead and
run your game and use the arrow keys to move the camera.

Quick C Sharp lesson:


With C Sharp we must define a variable's type. This is why you see 'float'. Other options are to use integers
for a type of variable, for example:

private int integerVariable;

Then if you wanted to convert assign a float's value to an integer you would do as follows:

integerVariable = (int)cameraDistance;

As cameraDistance is a float, and must be converted to an integer to assign it to an integer type.

Let's go through this code line by line:

tempVector = Vector3.forward;

Vectors initally just contain a position, if not set it will contain 0,0,0, Vectors can contain positions with no
magnitude (direction, their direction is pointed towards null I would guess), or positions with magnitude. If you're
used to eular angles you'd probably be very comfortable and familiar with using Vectors as angles. In this
example I am giving a Vector a direction. I want the Vector to point forwards along the Z axis. Vector3.forward
is the same as typing Vector3(0,0,1); Now my vector has a direction rather than just being at a position.

if ( Input.GetKey("left") ) // rotation the angle based on input


{
cameraAngleToPlayer = cameraAngleToPlayer - (Time.deltaTime * 50f);
} else if ( Input.GetKey("right") ) {
cameraAngleToPlayer = cameraAngleToPlayer + (Time.deltaTime * 50f);
}

Here we are simply changing a variable based on player input, by pressing right or left the variable will change,
this variable indicates the angle at which the camera shall be orbiting the player at.

tempVector = Quaternion.AngleAxis(cameraAngleToPlayer, Vector3.up) * tempVector;


// we are now rotating the Vector around the vertical (y) axis by an angle specificed in the variable
'cameraAngleToPlayer'

Here is where we are actually rotating our Vector which once faced forward along the Z axis. To rotate a vector
in Unity you can rotate it by multiplying it with a Quaternion. There is a formula for doing this. For example
'Vector3 = Quaterion * Vector3' shall work but 'Vector3 = Vector3 * Quaternion' wont work as there is an order as
to how things must be done. As the numerical value of cameraAngleToPlayer changes so does the direction
which tempVector is pointing hence the camera orbits around the player as input is received.

In fact we didn't even need to add 'tempVector = Vector3.forward' and could have simply made the last line of
code as follows:
tempVector = Quaternion.AngleAxis(cameraAngleToPlayer, Vector3.up) * Vector3.forward;
We are multiplying a Vector by an angle, this in turn rotates the Vector. In this case we do not want the
Quaternion, we want the Vector. Quaternions are used for rotations however we are placing the camera at a
position which changes based on an angle, and positions are Vector3 types. If we weren't focused on the
position and were working with rotations instead, we would go straight ahead and just rotate the Quaternion
instead of the Vector3.

Let's look at this next line of code:


cameraObject.transform.position = transform.position + (tempVector.normalized * cameraDistance) + new
Vector3(0,cameraHeight,0);

We are now directly setting the camera's position. Firstly we want to place it at the player's position, because
this is the player's script, 'transform.position' is the player's position. Next we want to add
'(tempVector.normalized * cameraDistance)' to the position. 'tempVector.normalized' gives the vector a
magnitude of 1, meaning that it is going to move the camera's position 1 unit along tempVector's direction and
we have the new direction of that vector because we multiplied it by a Quaternion. However we are also
multiplying tempVector.normalized by cameraDistance. This means that the camera will move along
tempVector's direction by the number of units specified in cameraDistance. If we set this at 10, then the camera
will be placed at a position 10 units along the vector 'tempVector'.

We are then moving the camera up along the Y (vertical) axis by adding 'new Vector3(0,cameraHeight,0);' If you
aren't used to C Sharp, there are certain circumstances that the syntax 'new' needs to be used otherwise you will
get an error, this has to do with memory management. I am not sure how to explain how or why this is needed,
a programming guru could. It is a difference between using Java and C Sharp.

So hopefully you understand how we are placing our camera relative to the player's position, based on an
angle.

Next part is making the camera look towards the player. We need to give the camera's rotation component a
Quaternion. A great function to use is LookRotation, which will convert the direction of a vector into a
Quaternion. In this case we simply subtract the camera's position from the player's position to get a vector from
the Camera to the Player, we can then convert the direction of this vector into a Quaternion and directly assign it
to our camera's rotation:

cameraObject.transform.rotation = Quaternion.LookRotation(transform.position -
cameraObject.transform.position);

So that's it! The very beginning stages of learning how to become familiar with Quaternions from Eular Angles.

Another function to look into is 'Vector3.RotateTowards', using it you can interpolate a vector's direction to
another vector's direction. For example, if you know the position of an object you desire to rotate towards. Find
the vector from the object you wish to look at to your own transform position, and rotate towards it from your
current position:

Vector3 rotateTowardsObject = objectToLookAt.transform.position – transform.position;


float rotateSpeed = 100f;
transform.forward = Vector3.RotateTowards (transform.forward, rotateTowardsObject, rotateSpeed *
Mathf.Deg2Rad * Time.deltaTime, 0);

And your object will rotate smoothly towards it's target (hopefully, unless my code is slightly off)

I hope this tutorial helps :)

-David
www.youtube.com/daveriser
www.rebelplanetcreations.com

S-ar putea să vă placă și