3D graphics tutorial

Rotating objects
My sister's handmade cards on Etsy.
Drawing of a pile of animals
A cube rotating about its z-axis.

Rotating things in three dimensions sounds complicated and it can be, but there are some simple rotations. For example, if we imagine rotating our cube around the z-axis (which points out of the screen), we are actually just rotating a square in two dimensions.

There is a reason to learn trigonometry

Rotating a point (x, 0) around the origin by θ.

We can simplify things further, by just looking at a single node at position (x, 0). Using simple trigonometry we can find that the position of the point after rotating it by θ around the origin is (x', y'), where,

x' = x × cos(θ)
y' = x × sin(θ)

If you don't understand where these equations came from, this video might help.

Rotating a point about the origin

Rotating a point (x, y) around the origin by β.

The example above allows us to rotate a point that starts on the x-axis about the origin, but what if it isn't on the x-axis? This requires some slightly more advanced trigonometry. If we call the distance between the point (x, y) and the origin r, and the angle between the line to (x, y) and x-axis, α then,

x = r × cos(α)
y = r × sin(α)

If we rotate by β to point (x', y'), then,

x' = r × cos(α + β)
y' = r × sin(α + β)

Using the trigonometric addition equations (derived here and here), we get,

x' = r × cos(α) cos(β) - r × sin(α) sin(β)
y' = r × sin(α) cos(β) + r × cos(α) sin(β)

Substituting in the values for x and y above, we get an equation for the new coordinates as a function of the old coordinates and the angle of rotation:

x' = x × cos(β) - y × sin(β)
y' = y × cos(β) + x × sin(β)

Writing a rotate function

Now we know the mathematics, we can write a function to rotate a node, or even better, our array of nodes, around the z-axis.

var rotateZ3D = function(theta) {
    var sin_t = sin(theta);
    var cos_t = cos(theta);
    
    for (var n = 0; n < nodes.length; n++) {
        var node = nodes[n];
        var x = node[0];
        var y = node[1];
        node[0] = x * cos_t - y * sin_t;
        node[1] = y * cos_t + x * sin_t;
    }
};
A square at a jaunty angle
Our cube is slightly more interesting, but not much.

This function loops through all the nodes in the node array, finds its current x and y coordinates and then updates them. We find sin(theta) and cos(theta) outside the loop so we only need to calculate it once.

We can test the function by calling it. Try rotating the cube by 30 degrees.

rotateZ3D(30);

You can see the complete code here.

See? Trigonometry can be useful!

Rotating in three dimensions

We can now rotate our cube in two dimensions, but it still looks like a square. What if we want to rotate our cube around the y-axis (veritcal axis). If we imagine looking down on our cube as we rotate it around the y-axis, what we would see is a rotating square, just like we do when we rotate about the z-axis.

So if we imagine our relabelling our axes, so the z-axis becomes the y-axis, we can come up with a new function for rotating around the y-axis. In this case, the y-coordinates of the node do not change.

var rotateY3D = function(theta) {
    var sin_t = sin(theta);
    var cos_t = cos(theta);
    
    for (var n = 0; n < nodes.length; n++) {
        var node = nodes[n];
        var x = node[0];
        var z = node[2];
        node[0] = x * cos_t - z * sin_t;
        node[2] = z * cos_t + x * sin_t;
    }
};

And we can use the same argument to create a function that rotates our cube around the x-axis:

var rotateX3D = function(theta) {
    var sin_t = sin(theta);
    var cos_t = cos(theta);
    
    for (var n = 0; n < nodes.length; n++) {
        var node = nodes[n];
        var y = node[1];
        var z = node[2];
        node[1] = y * cos_t - z * sin_t;
        node[2] = z * cos_t + y * sin_t;
    }
};

Again, we can test the code by calling the function.

rotateX3D(30);
rotateY3D(30);

You can see the complete code here. Try using the slider to change the values in the function calls.

User interaction

A cube looking like a cube
I told you it was a cube!

We can rotate the cube by adding function calls, but it's a lot more useful (and satisfying) if we can rotate it using the mouse. For this we need to create a mouseDragged() function. This function is automatically called whenever the mouse is dragged.

var mouseDragged = function() {
    rotateY3D(mouseX - pmouseX);
    rotateX3D(mouseY - pmouseY);
};

mouseX and mouseY are built-in variables that contain the current position of the mouse. pmouseX and pmouseY are built-in variables that contain the position of the mouse in the previous frame. So if the x-coordinate has increased (we move the mouse right), we send a postive value to rotateY3D() and rotate the cube counter-clockwise around the y-axis.

You can see for yourself here.