BlogContacts
BlogGamesContacts

{{item}}

Rotate the cube in space

05.08.2017

HTML5, Canvas

Source code
Consider the difference between parallel and perspective projection. Both are widely used in practice for different purposes.
In the previous example we have been rotating a square on the plane. Now let's move on to the three-dimensional space. To display on the screen plane the motion of a three-dimensional object, we should first create a three-dimensional object, rotate it by an angle, draw its projection and finally display on the screen the projection.

Your browser does not support Canvas

Parallel projectionThe type of projection, which is produced by parallel projection rays.

Your browser does not support Canvas

Perspective projectionThe type of projection, which is produced by projection rays, passing through a fixed point.
This article has continuation: Spinning spatial cross.
JavaScript
'use strict';

// We will draw two pictures at once.
// There will be one object and two of its projections
var canvas1 = document.getElementById('canvas1');
var canvas2 = document.getElementById('canvas2');

var canvas_context1 = canvas1.getContext('2d');
var canvas_context2 = canvas2.getContext('2d');

// Move the origin of coordinates to the center of the block
canvas_context1.translate(canvas1.width / 2, canvas1.height / 2);
canvas_context2.translate(canvas2.width / 2, canvas2.height / 2);

// The figure will be set as a combination of four planes.
// Each plane is a combination of four points
var arr_t = [
// Front face
[{x:-100, y:-100, z:-100},
    {x:100, y:-100, z:-100},
    {x:100, y:100, z:-100},
    {x:-100, y:100, z:-100}],
// Right face
[{x:100, y:-100, z:-100},
    {x:100, y:-100, z:100},
    {x:100, y:100, z:100},
    {x:100, y:100, z:-100}],
// Left face
[{x:-100, y:-100, z:-100},
    {x:-100, y:-100, z:100},
    {x:-100, y:100, z:100},
    {x:-100, y:100, z:-100}],
// Rear face
[{x:-100, y:-100, z:100},
    {x:100, y:-100, z:100},
    {x:100, y:100, z:100},
    {x:-100, y:100, z:100}]];

// Center of the figure.
// We'll make a turn around it
var t0 = {x:0, y:0, z:0};

// Rotation angle in degrees
var deg = 0;

// For perspective projection:
// Distance between the observer and the object.
// Cannot be smaller than the size of the object,
// in our case 200px
var a = 300;

// The size of the object on the screen in (%)
var k = 70;

// Current figure
var arr_tt = [];
for (var i = 0; i < arr_t.length; i++) {
    arr_tt[i] = arr_t[i].slice();
}

// Current projection
var arrProj;

// Set the repaint screen function with the rotation of the figure.
// Then this function will need to be inserted into the variable
// window.onload
function repaint() {

    // First, clear the screen - repaint with white color
    clearScreen(canvas1, canvas_context1, 'rgb(255,255,255)');
    clearScreen(canvas2, canvas_context2, 'rgb(255,255,255)');

    // Now turn the original figure by an angle on
    // the axis (Y) and overwrite the current figure
    for (var i = 0; i < arr_t.length; i++) {
        for (var j = 0; j < arr_t[0].length; j++) {
            arr_tt[i][j] = rotateByDegreeY(t0, arr_t[i][j], deg);
        }
    }

    // Get a parallel projection
    arrProj = getParallelProjection(arr_tt);

    // Draw a parallel projection
    canvas_context1.lineWidth = 2; // black translucent
    strokeFigure(canvas_context1, arrProj, 'rgba(0,0,0,0.5)');

    // Get a perspective projection
    arrProj = getPerspectiveProjection(arr_tt);

    // Draw a perspective projection in a nearby window
    canvas_context2.lineWidth = 2; // black translucent
    strokeFigure(canvas_context2, arrProj, 'rgba(0,0,0,0.5)');

    // Increase an angle
    deg += 1;
}

// Additional functions

// Get a parallel projection of a figure on the screen plane
function getParallelProjection(arr) {

    var arr_new = [];

    for (var i = 0; i < arr.length; i++) {
        arr_new[i] = [];
        for (var j = 0; j < arr[0].length; j++) {
            arr_new[i][j] = {};
            arr_new[i][j].x = arr[i][j].x;
            arr_new[i][j].y = arr[i][j].y + arr[i][j].z / 4;
        }
    }

    return arr_new;
}

// Get a perspective projection
function getPerspectiveProjection(arr) {
    var arr_new = [];

    for (var i = 0; i < arr.length; i++) {
       arr_new[i] = [];
       for (var j = 0; j < arr[0].length; j++) {
          arr_new[i][j] = {};
          arr_new[i][j].x = (a / 100 * k) * arr[i][j].x / (arr[i][j].z + a);
          arr_new[i][j].y = (a / 100 * k) * arr[i][j].y / (arr[i][j].z + a);
       }
    }

    return arr_new;
}

// Fill the screen with the specified color
function clearScreen(canvas, context, color) {
    context.fillStyle = color;

    context.beginPath();
    context.fillRect(- canvas.width / 2,
                     - canvas.height / 2,
                       canvas.width,
                       canvas.height);
    context.closePath();
    context.fill();
}

// Draw a figure through points from an array
function strokeFigure(context, arr, color) {
    context.strokeStyle = color;
    context.fillStyle = color;

    for (var i = 0; i < arr.length; i++) {
        context.beginPath();
        for (var j = 0; j < arr[0].length; j++) {
            if (j == 0) {
                context.moveTo(arr[i][j].x, arr[i][j].y);
            } else {
                context.lineTo(arr[i][j].x, arr[i][j].y);
            }
        }
        context.closePath();
        context.stroke();
    }
}

// Turn the point t(x,y,z) by an angle (deg)
// on the axis (Y) relative to the point t0(x,y,z)
function rotateByDegreeY(t0, t, deg) {

    var t_new = {};

    // Translate the rotation angle from degrees to radians
    var rad = (Math.PI / 180) * deg;

    // Calculate the coordinates of the new point according to the formula
    t_new.x = t0.x+(t.x-t0.x)*Math.cos(rad)-(t.z-t0.z)*Math.sin(rad);
    t_new.y = t.y;
    t_new.z = t0.z+(t.x-t0.x)*Math.sin(rad)+(t.z-t0.z)*Math.cos(rad);

    // Return the received value
    return t_new;
}

// Set the screen repaint interval
window.onload = function() {
    setInterval(repaint, 100);
};
That's all folks! In addition consider an example of rotation on all three axes at once.
Parallel projection

Your browser does not support Canvas

Perspective projection

Your browser does not support Canvas

Privacy policy
Back to Top