Unity and Vector3, Quaternion, classes, structs, and instances Assistant professor in computer games Perttu Hämäläinen
Unity and Vector3, Quaternion,
classes, structs, and instances
Assistant professor in computer games
Perttu Hämäläinen
Vector3 • A collection of three numbers: x,y,z.
• Can represent place, displacement, velocity – anything
with a 3d direction and magnitude
• Vector2 is the same, but with just x,y
• Vector1 = scalar, just a single number
(0,0)
Vector2 a = new Vector2(5,5);
(5,0)
(0,5)
y
x
Vector scaling (multiplication with scalar)
• Scalar multiplication only affects magnitude, not
direction
0,0
Vector2 a = new Vector2(3,1);
Vector2 b = a * 3;
or alternatively,
Vector2 b = a;
b.Scale(3);
Vector scaling example
• Make an object move forward 5 m/s
rigidbody.velocity = transform.forward * 5.0f;
• transform.forward is a unit vector (of magnitude 1.0),
points along the game object’s z axis. This gives us the
direction. To get the velocity vector, we scale the
direction appropriately.
Vector addition
0,0
Vector2 a = new Vector2(3,1);
Vector2 b = new Vector2(1,3);
Vector2 c = a + b;
Vector addition
0,0
Vector2 a = new Vector2(3,1);
Vector2 b = new Vector2(1,3);
Vector2 c = a - b;
• Remember that a – b = a + (-1.0 * b)
Vector addition and scaling example
• Translate an object without a rigidbody with a constant speed
independent of game frame rate. Code in Update()
transform.position += transform.forward * speed
* Time.deltaTime;
• transform.position and transform.forward are both Vector3
• transform.forward * speed is the velocity vector
• need to scale with Time.deltaTime to make motion
independent of game fps
Scaling the moved distance based on
Time.deltaTime
• Object moves at constant speed -> travelled distance
grows linearly as a function of time
distance
time (seconds)
distance per frame at 10 fps, deltaTime = 1/10
1.0 2.0
distance per frame at 1 fps,
deltaTime = 1
Vector addition and scaling example 2
• Place a camera behind and above this gameobject,
looking at this gameobject
camera.transform.position = gameObject.transform.position
- gameObject.transform.forward * 2.0f
+ Vector3.up * 2.0f;
camera.transform.LookAt(gameObject.transform.position);
• Vector3.up is a constant, equal to new Vector3(0,1,0).
Note that using uppercase Vector3 denotes the struct or
class instead of a specific instance (see next slide...)
• The transform.LookAt() method rotates the object so
that it’s z-axis (transform.forward) points at the target
Classes, structs and instances
• Related to how things are stored in computer memory
Memory:
Scale()
0,1,0
1,0,0
...
...
...
...
...
...
...
...
...
...
Vector3 (code, static
and const)
//Vector3 definition (C#)
struct Vector3
{
//global (static, const) data
void Scale(float scale)
{
...
}
static Vector3 up=new Vector3(0,1,0);
const Vector3 right=new Vector3(1,0,0);
//member variables
float x,y,z;
};
unused (free) memory
Classes, structs and instances • The new operator allocates instances in memory
• Class/struct data stored only once, member variables for each instance
Memory:
Scale()
0,1,0
1,0,0
1,2,3
3,2,1
...
...
...
...
...
...
...
Vector3
Vector3 a=new Vector3(1,2,3);
Vector3 b=new Vector3(3,2,1);
a (instance data)
b (instance data)
Classes, structs and instances
• Important! Vector3 is a struct (a value type). For
structs, a new instance is allocated and members copied
when assigning Vector3 c=b;
Memory:
Scale()
0,1,0
1,0,0
1,2,3
3,2,1
3,2,1
...
...
...
...
...
...
...
Vector3 struct data
Vector3 a=new Vector3(1,2,3);
Vector3 b=new Vector3(3,2,1);
Vector3 c=b;
a
b
c
Classes, structs and instances
• In this case, changing c doesn’t change b
Memory:
Scale()
0,1,0
1,0,0
1,2,3
3,2,1
10,2,1
...
...
...
...
...
...
...
Vector3 struct data
Vector3 a=new Vector3(1,2,3);
Vector3 b=new Vector3(3,2,1);
Vector3 c=b;
c.x=10; a
b
c
Classes, structs and instances
• If Vector3 was not a struct, but a class like GameObject,
only a reference would be allocated when assigning (=)
Memory:
Scale()
0,1,0
1,0,0
1,2,3
3,2,1
983241
...
...
...
...
...
...
...
Vector3
Vector3 a=new Vector3(1,2,3);
Vector3 b=new Vector3(3,2,1);
Vector3 c=b;
a
b
c (reference to b)
Classes, structs and instances
• To be more precise, the memory would look like this...
Memory:
Scale()
0,1,0
1,0,0
1,2,3
3,2,1
983241
983242
983242
...
...
...
...
...
Vector3
Vector3 a=new Vector3(1,2,3);
Vector3 b=new Vector3(3,2,1);
Vector3 c=b;
Vector 3 instance
Vector 3 instance
a (reference)
b (reference)
c (reference, equal to b)
Classes, structs and instances
• In this case, changing member variables of c changes b.
The references c and b denote the same object.
Memory:
Scale()
0,1,0
1,0,0
1,2,3
10,2,1
983241
...
...
...
...
...
...
...
Vector3 class data
Vector3 a=new Vector3(1,2,3);
Vector3 b=new Vector3(3,2,1);
Vector3 c=b;
c.x=10;
a
b
c (reference to b)
Classes, structs and instances
• Remember the difference, otherwise you’ll encounter
strange bugs
Memory:
Scale()
0,1,0
1,0,0
1,2,3
10,2,1
983241
...
...
...
...
...
...
...
Vector3 class data
Vector3 a=new Vector3(1,2,3);
Vector3 b=new Vector3(3,2,1);
Vector3 c=b;
c.x=10;
a
b
c (reference to b)
Classes, structs and instances
• However, we can make a copy by allocating a new
object and explicitly copying the data.
Memory:
Scale()
0,1,0
1,0,0
1,2,3
3,2,1
10,2,1
...
...
...
...
...
...
...
Vector3 class data
Vector3 a=new Vector3(1,2,3);
Vector3 b=new Vector3(3,2,1);
Vector3 c=new Vector3(b);
c.x=10;
a
b
c
Memory allocation and performance
issues
• You should avoid using new in FixedUpdate() or
Update() because otherwise you will get occasional
framerate drops because of memory allocation problems
(heap fragmentation, garbage collection).
• However, using new for structs doesn’t cause fps
glitches, because structs are allocated from stack
memory instead of heap, which is faster
Javascript and value types
class Vector3 extends System.ValueType
{
var x:float;
var y:float;
var z:float;
}
Quaternion = rotation
• Fast and intuitive use of Vector3 etc. requires
repetition.
Quaternion = rotation
• Fast and intuitive use of Vector3 etc. requires
repetition.
• Explaining how things like vector math work helps in
learning, but with enough repetition, we can learn, e.g.,
new verbs and grammar based on context only
Quaternion = rotation
• Fast and intuitive use of Vector3 etc. requires
repetition.
• Explaining how things like vector math work helps in
learning, but with enough repetition, we can learn, e.g.,
new verbs and grammar based on context only
• A quaternion is a mathematical tool for operating with
rotations. It’s a collection (in Unity, a struct) of 4
numbers: x,y,z,w.
Quaternion = rotation
• Fast and intuitive use of Vector3 etc. requires
repetition.
• Explaining how things like vector math work helps in
learning, but with enough repetition, we can learn, e.g.,
new verbs and grammar based on context only
• A quaternion is a mathematical tool for operating with
rotations. It’s a collection (in Unity, a struct) of 4
numbers: x,y,z,w.
• Quaternion math is difficult to understand, but using
Unity quaternions is fairly easy
Why quaternion instead of Euler angles
• 3d modeling packages, including Unity Inspector view,
let users manipulate rotation using Euler angles (rotation
around x, y and z angles)
• Internally, there’s some computational problems (gimbal
lock) -> most software use quaternions
• Unity allows you to convert between eulers and
quaternions
Quaternion examples
//rotate v (Vector3) 90 degrees around y axis using Eulers
v *= Quaternion.Euler(0,90,0)
//rotate v (Vector3) 90 degrees around a given axis (here Vector3.up)
v *= Quaternion.AngleAxis(90,Vector3.up)
//Rotate head partially to the direction of a target.
//In reality, we follow partly using eyes, partly by turning our head.
//Here, we limit the head turning to 45 degrees, assuming that we start
//from a neutral rotation. Slerp (spherical linear interpolation) returns
//a rotation that is between the given two rotations
Vector3 headToTarget = targetPosition – headTransform.Position;
Quaternion fullRotation = Quaternion.LookRotation(headToTarget);
Quaternion partialRotation = Quaternion.Slerp(headTransform.rotation,
fullRotation,0.5f);
headTransform.rotation = Quaternion.RotateTowards(headTransform.rotation,
partialRotation,45);
• Vector3 is rotated by multiplying it with a Quaternion.
About radians and degrees
• Some Unity rotation helpers assume that given angles
are in radians. 360 degrees = 2π radians
• π is in Unity Mathf.PI
• 0 radians = 0 degrees.
• 0.5π radians = 90 degrees
• π radians = 180 degrees
Summary
• Vector3 and Vector2 scaling and adding/subtracting
often needed
• Quaternion provides rotation utilities – need to know
how to use, don’t need to know the numbers inside.
• structs (value types) allocated from stack -> use when
possible, new Vector3() doesn’t have an additional cost
• Remember that for classes (reference types),
assignment only copies a reference