C++ Fast Vector3 Class


Every single entity in a 3D game world will make use of the Vector3 class. A position, a movement direction, gravity, the points in some models geometry, particles or sometimes even rotations will depend on Vector3. If there is one Class that is used in every 3D game on the planet, then it's probably Vector3. Since it will be used so frequently, it's very important for us to implement it as fast and lightweight as possible.

A Vector3 basically consists of x, y and z as float values and a few operations like distance calculation. A commonly used implementation is straight forward like this:

class Vector3
    float x, y, z;

    Vector3(float _x, float_y, float _z)
     : x(_x), y(_y), z(_z)
    void inverse()
        x = -x;
        y = -y;
        z = -z;        

// Usage example:
void test()
    Vector3 v(0.0f, 1.0f, 2.0f);

Many people will think of this when they think about a perfect implementation of Vector3, which makes perfect sense.
The main reason that we are programming in C++ is the performance though. Because of that, our goal will be to not just have a good Vector3 class but also one that is as fast as possible: We will do this by not using a class at all but instead sticking with simple arrays of float values (which is faster and saves us a lot of trouble with operators).

Here is an example:

void inverse(float v[3])
    v[0] = -v[0];  // that's x
    v[1] = -v[1];  // that's y
    v[2] = -v[2];  // that's z

// Usage example:
void test()
    // Create out Vector3 - which is simply a float array
    float v[3] = {0.0f, 1.0f, 2.0f);
    // Use our Vector3 inverse function just for fun

As we see here, it does about the same thing, yet we save some calculations when not creating a special Vector3 object, but just using a float array that holds three values. Notice how we don't use x, y and z but instead v[0], v[1], v[2] which means our "x" is in the first position of the array, our "y" in the second and our "z" in the third.

What seems like a minor change could make all the difference between having 60 FPS or just 55 FPS in our games, hence why we like the faster example (the second one) more. Besides, using arrays and indices will make it easier for us to implement some more complicated algorithms like linear (in)dependence.

Let's take a look at a few important functions that we will have to implement in order to have a halfway complete Vector3 "class"(to be exact: it's not really a class, it's just a few functions).

Note: it's a good idea to use C++ namespaces here and put all Vector3 functions into one File so it looks like this:

inline void vec3::inverse(float v[3])
    v[0] = -v[0];
    v[1] = -v[1];
    v[2] = -v[2];

Using the inline operator is a good idea for our Vector3 functions, it saves some computations and instead will increase our game.exe file size a bit - which is a good deal since every FPS increase matters.

Note: If you don't know what to do with this "vec3::" or "inline" part, just leave it out for now, it will also work without it.

Implementation of Vector3 Inverse

Since it was already used above, let's talk about the inverse function first.

inline void vec3::inverse(float v[3])
    v[0] = -v[0];
    v[1] = -v[1];
    v[2] = -v[2];

As we can see, it simply inverses each component of our Vector3. For example, if we have (0, 1, -2) it will change it to (0, -1, 2). This process is called inverting and it applies to many datatypes, not just to Vector3. While we might not need it for the most simple games, it will definitely come in handy when implementing some more interesting algorithms.

Implementation of Vector3 Compare

Its very important that we understand how to properly compare floating point values in C++.
Since we do understand it, we can use this knowledge and apply it to our Vector3 very easily:

inline bool vec3::cmp(const float v0[3], const float v1[3]) 
    // compare with epsilon
    return (cmpf(v0[0], v1[0]) &&
            cmpf(v0[1], v1[1]) &&
            cmpf(v0[2], v1[2]));

Note: const makes sure that we don't change any value of the two vectors in this function, it's basically one of many best practices in order to create better software. If this is too overwhelming for you, then feel free to leave const away until you know what it does.

The function compares the first Vectors "x" value with the second ones "x" value, then the same with "y" and "z". If all three times the cmpf function returned true, then the result will be true as well.

We will use this function about everywhere in a game. For example if a player is running towards a certain point, we will have to find out if he already reached it by (for example) comparing his position with the point like this:

bool hasReachedPosition(float[3] goal)
    // has reached it if they are qual
    return vec3::cmp(playerPosition, goal);

Implementation of Vector3 Copy

The copy function does what its name already says, it copies a Vector3:

inline void vec3::copy(const float v[3], float out[3])
    out[0] = v[0];
    out[1] = v[1];
    out[2] = v[2];

Notice how the first Vector3 "v" is const, that guarantees us that the function doesn't change it in any case.

A common usage would be for physics. We want to find out if a player can still move a bit forward or if he would hit a wall then. To do so we could just change the players position and then find out if he is in the wall already, but a more elegant solution would be to copy it and then change and test the copy, so it doesn't look like the player is in the wall. Example:

bool canGoForward()
    // create a new Vector3
    float[3] dummy;
    // Copy the players position into it
    // (without changing the players position at all)
    vec3::copy(playerPosition, dummy);
    // Pretend that he would move forward
    // (in this case in 'x' direction)
    dummy[0] = dummy[0] + 1.0f;

    // Return true if it does not intersect with the wall
    return (intersectsWithWall(dummy) == false);

This is more a pseudo-code and would be done slightly different in reality, but it's still a good example to show what copy can be used for.

Implementation of Vector3 Translate

Very often we will have to add a Vector3 to another Vector3, this is what is usually called Translation. The implementation is very straight forward, since we just have to add two float values each time (for x, for y and for z). The only thing that's interesting is that we have no return value, but a third parameter that will be our result. Example:

float[3] v = {1, 1, 1};
float[3] w = {2, 2, 2};

// add 'v' and 'w' and store the result in 'u'
float[3] u;
vec3::translate(v, w, u);

Here is the implementation of our translate function:

inline void vec3::translate(const float v0[3], const float v1[3], float out[3])
    out[0] = v0[0] + v1[0];
    out[1] = v0[1] + v1[1];
    out[2] = v0[2] + v1[2];

It's almost straightforward, except for the fact that the function does not return float[3] but instead the third parameter is the result. The reason is that in C++ a function simply can't return float[3], it would lead to compilation errors.

Note: the function is often called "add"(since it just adds two vectors). But since we are mostly in the computer graphics area here, we will call it Translate.

Implementation of Vector3 Scale

The scale function is very similar to the Translate function, but this time it's multiplication instead of addition:

inline void vec3::scale(const float v0[3], const float v1[3], float out[3])
    out[0] = v0[0] * v1[0];
    out[1] = v0[1] * v1[1];
    out[2] = v0[2] * v1[2];

If our player gets a Level-Up, we might want to increase his model size a bit by 10%. In cases like that we will need a Vector3 Scale function, here is a usage example:

void playerLevelUp()
    // increase his health
    health = health + 10;
    // increase his model size (so he looks bigger)
    // what we need to do is scale each point in the players model
    float s[3] = {1.1f, 1.1f, 1.1f}; // makes it 10% bigger in each direction
    for each Point in Players model do {
       float[3] newPoint;
       vec3::scale(point, s, newPoint);    
       // and so on...      

Implementation of Vector3 Distance

Let's come to the distance function mentioned in the foreword. The distance is a bit more complicated to calculate, but still no reason to get confused. It's very simple:

inline float vec3::dist(const float p1[3], const float p2[3])
    float x = p1[0]-p2[0];
    float y = p1[1]-p2[1];
    float z = p1[2]-p2[2];
    return sqrt(x*x + y*y + z*z);

We could use that function when implementing a Monster that attacks a player if he is in a certain range to the monster, like this:

void updateMonster()
    if (vec3::dist(monsterPosition, playerPosition) < 10.0f) {


With the previously implemented functions we now have the basics of the Vector3 class in a clean and fast way.

As a small exercise, feel free to implement the "Length", "Dot Product", "Norm" and "Set Length" functions as well, since they will be needed often. Wikipedia will provide you with enough information about what exactly they do and the functions above will help you to understand how to implement them in a fast and elegant way.