Vec3: A Simple Vector Class in C++

This is really the second post of three updating an earlier post on how to write some simple FPS-type controls for OpenGL – last post we looked at a FpsManager class so we could get frame timings to implement framerate independent movement. This time, we’re looking at a simple Vec3 class which stores 3D coordinates and helps to perform some operations on them. This is going to form part of the Camera class in the final part, but I thought I’d put it here on its own so it can be re-used.

There’s probably about ten million different vector classes out there, but I really wanted to write my own so I understood exactly how it worked, and I’ve commented it pretty heavily in the process – so hopefully if you’re looking for a vector class you might be able to look at this one, see how it works and what it does, and take and modify it for your own work.

Before skipping to the code, let’s just take a quick look at what it does – it packages up 3 values called x, y and z, and allows us to easily manipulate them. Quite what you store in these values is up to you, it could be a vertex position, or a direction vector, or a RGB colour – anything that has three values, really.

If we were dealing with two vertexes, we can do stuff like this:

    // Define two initial vectors
    Vec3<double> vector1(1, 2, 3); // A coordinate +1 on the X axis (horiz), +2 on the Y axis (vert), and +3 on the Z axis (depth)
    Vec3<double> vector2(4, 5, 6); // A coordinate +4 on the X axis (horiz), +5 on the Y axis (vert), and +6 on the Z axis (depth)
    // Create a new vector which is the sum of these two vectors added together
    Vec3<double>result = vector1 + vector2;
    result.display();           // (5, 7, 9)
    // Add the first vector to our result vector
    result += vector1;
    result.display();           // 6, 9, 12
    // Subtract the second vector from our result vector
    result -= vector2;
    result.display();           // 2, 4, 6
    // Divide our result vector by the scalar value 2
    result /= 2;
    result.display();           // 1, 2, 3
    // Multiply both vectors together and assign to our result vector (this is a dot-product
    // operation, but we have specific dot product functions we can use, too)
    result = vector1 * vector2;
    result.display();           // 4, 10, 18
    // Multiply our result vector by 2
    result *= 2;
    result.display();           // 8, 20, 36
    // Normalise our result vector so that all values fall within the range -1 to +1
    result.display();           // 0.190693, 0.476731, 0.858116
     // Calculate the distance between two points in 3D space
    double distance = Vec3<double>::getDistance(vector1, vector2);
    cout << "Distance between points: " << distance << endl; // 5.19615
    // Dot products only work on normalised values (i.e. each x/y/z value in the vector must be in the range -1 to +1)
    // So remember to normalise your vectors before computing the dot product!
    double dotProduct = Vec3<double>::dotProduct(vector1, vector2);
    cout << "Dot product: " << dotProduct << endl;           // 0.974632
    // Define some vectors pointing up, down, left, and right
    Vec3<double> up(   0,  1, 0);
    Vec3<double> down( 0, -1, 0);
    Vec3<double> left(-1,  0, 0);
    Vec3<double> right(1,  0, 0);
    // ------------ Dot Product Tests ------------
    // The dot product of two vectors pointing the same direction is 1
    dotProduct = Vec3<double>::dotProduct(up, up);
    cout << "Dot product of up and up: " << dotProduct << endl;
    // The dot product of two vectors which are perpendicular to each other is is 0
    dotProduct = Vec3<double>::dotProduct(up, right);
    cout << "Dot product of up and right: " << dotProduct << endl;
    // The dot product of two vectors pointing in opposite directions is -1
    dotProduct = Vec3<double>::dotProduct(up, down);
    cout << "Dot product of up and down: " << dotProduct << endl;
    // ------------ Cross Product Tests ------------
    // The cross product of a vector is the vector which is perpendicular to the plane made
    // by the two vectors specified. Whether it points "up" or "down" depends on the
    // handedness of the coordinate system and/or the order of vectors provided.
    // Test 1
    Vec3<double> crossProduct = Vec3<double>::crossProduct(up, right);
    // x = 0, y = 0, z = -1 (i.e. the vector perpendicular to up and right points INTO the screen)
    // Test 2
    crossProduct = Vec3<double>::crossProduct(right, up);
    // x = 0, y = 0, z = 1 (i.e. the vector perpendicular to right and up points OUT from screen)

Seems pretty easy to work with to me…

Here’s the code for the Vec3 class itself as a templatised, header-only C++ .hpp file – just include the Vec3.hpp class and you’re good to go:

#ifndef VEC3_HPP
#define VEC3_HPP
#include <iostream>
template <class T> class Vec3
        // A Vec3 simply has three properties called x, y and z
        T x, y, z;
        // ------------ Constructors ------------
        // Default constructor
        Vec3() { x = y = z = 0; };
        // Three parameter constructor
        Vec3(T xValue, T yValue, T zValue)
            x = xValue;
            y = yValue;
            z = zValue;
        // ------------ Getters and setters ------------
        void set(const T &xValue, const T &yValue, const T &zValue)
            x = xValue;
            y = yValue;
            z = zValue;
        T getX() const { return x; }
        T getY() const { return y; }
        T getZ() const { return z; }
        void setX(const T &xValue) { x = xValue; }
        void setY(const T &yValue) { y = yValue; }
        void setZ(const T &zValue) { z = zValue; }
        // ------------ Helper methods ------------
        // Method to reset a vector to zero
        void zero()
            x = y = z = 0;
        // Method to normalise a vector
        void normalise()
            // Calculate the magnitude of our vector
            T magnitude = sqrt((x * x) + (y * y) + (z * z));
            // As long as the magnitude isn't zero, divide each element by the magnitude
            // to get the normalised value between -1 and +1
            if (magnitude != 0)
                x /= magnitude;
                y /= magnitude;
                z /= magnitude;
        // Static method to calculate and return the scalar dot product of two vectors
        // Note: The dot product of two vectors tell us things about the angle between
        // the vectors. That is, it tells us if they are pointing in the same direction
        // (i.e. are they parallel? If so, the dot product will be 1), or if they're
        // perpendicular (i.e. at 90 degrees to each other) the dot product will be 0,
        // or if they're pointing in opposite directions then the dot product will be -1.
        // Usage example: double foo = Vec3<double>::dotProduct(vectorA, vectorB);
        static T dotProduct(const Vec3 &vec1, const Vec3 &vec2)
            return vec1.x * vec2.x + vec1.y * vec2.y + vec1.z * vec2.z;
        // Non-static method to calculate and return the scalar dot product of this vector and another vector
        // Usage example: double foo = vectorA.dotProduct(vectorB);
        T dotProduct(const Vec3 &vec) const
            return x * vec.x + y * vec.y + z * vec.z;
        // Static method to calculate and return a vector which is the cross product of two vectors
        // Note: The cross product is simply a vector which is perpendicular to the plane formed by
        // the first two vectors. Think of a desk like the one your laptop or keyboard is sitting on.
        // If you put one pencil pointing directly away from you, and then another pencil pointing to the
        // right so they form a "L" shape, the vector perpendicular to the plane made by these two pencils
        // points directly upwards.
        // Whether the vector is perpendicularly pointing "up" or "down" depends on the "handedness" of the
        // coordinate system that you're using.
        // Further reading:
        // Usage example: Vec3<double> crossVect = Vec3<double>::crossProduct(vectorA, vectorB);
        static Vec3 crossProduct(const Vec3 &vec1, const Vec3 &vec2)
            return Vec3(vec1.y * vec2.z - vec1.z * vec2.y, vec1.z * vec2.x - vec1.x * vec2.z, vec1.x * vec2.y - vec1.y * vec2.x);
        // Easy adders
        void addX(T value) { x += value; }
        void addY(T value) { y += value; }
        void addZ(T value) { z += value; }
        // Method to return the distance between two vectors in 3D space
        // Note: This is accurate, but not especially fast - depending on your needs you might
        // like to use the Manhattan Distance instead:
        // There's a good discussion of it here:
        // The gist is, to find if we're within a given distance between two vectors you can use:
        // bool within3DManhattanDistance(Vec3 c1, Vec3 c2, float distance)
        // {
        //      float dx = abs(c2.x - c1.x);
        //      if (dx > distance) return false; // too far in x direction
        //      float dy = abs(c2.y - c1.y);
        //      if (dy > distance) return false; // too far in y direction
        //      float dz = abs(c2.z - c1.z);
        //      if (dz > distance) return false; // too far in z direction
        //      return true; // we're within the cube
        // }
        // Or to just calculate the straight Manhattan distance you could use:
        // float getManhattanDistance(Vec3 c1, Vec3 c2)
        // {
        //      float dx = abs(c2.x - c1.x);
        //      float dy = abs(c2.y - c1.y);
        //      float dz = abs(c2.z - c1.z);
        //      return dx+dy+dz;
        // }
        static T getDistance(const Vec3 &v1, const Vec3 &v2)
            T dx = v2.x - v1.x;
            T dy = v2.y - v1.y;
            T dz = v2.z - v1.z;
            return sqrt(dx * dx + dy * dy + dz * dz);
        // Method to display the vector so you can easily check the values
        void display()
            std::cout << "X: " << x << "\t Y: " << y << "\t Z: " << z << std::endl;
        // ------------ Overloaded operators ------------
        // Overloaded addition operator to add Vec3s together
        Vec3 operator+(const Vec3 &vector) const
            return Vec3<T>(x + vector.x, y + vector.y, z + vector.z);
        // Overloaded add and asssign operator to add Vec3s together
        void operator+=(const Vec3 &vector)
            x += vector.x;
            y += vector.y;
            z += vector.z;
        // Overloaded subtraction operator to subtract a Vec3 from another Vec3
        Vec3 operator-(const Vec3 &vector) const
            return Vec3<T>(x - vector.x, y - vector.y, z - vector.z);
        // Overloaded subtract and asssign operator to subtract a Vec3 from another Vec3
        void operator-=(const Vec3 &vector)
            x -= vector.x;
            y -= vector.y;
            z -= vector.z;
        // Overloaded multiplication operator to multiply two Vec3s together
        Vec3 operator*(const Vec3 &vector) const
            return Vec3<T>(x * vector.x, y * vector.y, z * vector.z);
        // Overloaded multiply operator to multiply a vector by a scalar
        Vec3 operator*(const T &value) const
            return Vec3<T>(x * value, y * value, z * value);
        // Overloaded multiply and assign operator to multiply a vector by a scalar
        void operator*=(const T &value)
            x *= value;
            y *= value;
            z *= value;
        // Overloaded multiply operator to multiply a vector by a scalar
        Vec3 operator/(const T &value) const
            return Vec3<T>(x / value, y / value, z / value);
        // Overloaded multiply and assign operator to multiply a vector by a scalar
        void operator/=(const T &value)
            x /= value;
            y /= value;
            z /= value;

Next post, we’re going to be implementing a FPS-style camera class using this Vec3 class to move around a 3D scene – and because of all our hard work in getting this vector class together, it’s going to make moving the camera around a doddle =D


Simple OpenGL FBO Textures

I was playing around with FBOs and rendering to textures the other week and came up with this. A spinning yellow torus is rendered to a texture, then a second spinning torus is textured using the texture we just created of the first spinning torus… Yeah, I need to stop using donuts as my test objects.

Full source code & shaders after the jump…

Continue reading Simple OpenGL FBO Textures

How To: Syntax highlight GLSL shaders in Gedit

GLSL shaders share a lot in common with the C language, and Gedit can syntax highlight C/C++ and a host of other languages – so why not GLSL shaders? Here’s a simple way to make it happen…

1.) Gedit uses gtksourceview for its syntax highlighting rules – so find out where that’s located on your distro with the following:

locate gtksourceview | grep /c.lang

Once you’ve got the location of the c.lang file, navigate there in the bash (on Ubuntu it’s in /usr/share/gtksourceview-2.0/language-specs).

2.) Make a copy of the c.lang file in case you accidentally stuff it up (optional, but better safe than sorry):

sudo cp c.lang c.lang.ORIG

3.) Open the file with your text editor of choice and modify the c.lang file to add in additional file extensions which should be syntax highlighted as per the c.lang definitions:

gksudo gedit ./c.lang

A couple of lines into the file (after the comments at the top) you’ll see the following:

<property name="globs">*.c;</property>

Assuming you’re ending your vertex shaders with .vp and your fragment shaders with .fp (if you’re using .vert and .frag or such just substitute appropriately), change the line to read:

<property name="globs">*.c;*.vp;*.fp</property>

Save it, close gedit, and open a .vp or .fp file with Gedit – syntax highlighty goodness is rightfully yours. Of course, this is normal C highlighting, not true GLSL highlighting – but it’s a good start.

If you wanted to add things like vec3, uniform etc. then you can find the following sections in the c.lang file and add ’em in yourself:

<context id="keywords" style-ref="keyword" class="keyword">
<context id="types" style-ref="type" class="type">


C++/OpenGL/GLSL Texture Manipulation

Just learning some GLSL and playing about with vertex and fragment shaders – not a bad first start, but it’s going to take a significant amount of time and effort to get to really writing some descent shaders – it’s just very, very different from fixed-pipeline stuff… What you’re looking at is a texture where I’ve drawn some stuff on it in bright red, and then in the fragment shader anything found in the texture to be bright red gets discarded, effectively leaving in empty, like a cut-out =D

All in, the project’s around 500 lines of source, with the shaders being merely:

Vertex Shader

#version 110 // Olde...
varying vec2 vTexCoord; // varying is now deprecated.. will re-write soon
void main(void)
   vTexCoord = gl_MultiTexCoord0; 
   gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; // 3D vertex -> 2D window position transformation

Fragment Shader

sampler2D myTexture;    // Apparently this should not be a uniform variable as you shouldn't loop through uniform variables for performance reasons...
varying vec2 vTexCoord; // Pass through from our vertex shader. Should be type "in" in more recent versions of GLSL
void main (void) 
   vec4 color = texture2D(myTexture, vTexCoord); 
   if (color.r > 0.9 && (color.g < 0.15 && color.b < 0.15))
   gl_FragColor = color;

The Linux Code::Blocks project will all source & image can be found below, but you’ll need to have or install libGL, libGLEW, libglfw, libIL, libILU, libILUT for it to work right out of the box. The linkage details are all in the Code::Blocks project file (and also in the .depend file if you don’t use C::B) so you can see what you need if there’s anything missing.


Update: Ha! Hadn’t thought of this before, but I guess what I’m really doing is Chroma-Keying (or Colour-Keying, whatever you prefer)… And you can do the same thing in SDL/OpenGL without using any shaders like this.