BlogContacts
BlogGamesContacts

{{item}}

Spinning spatial cross

19.12.2017

HTML5, Canvas

Source code
Two variants of the same figure. Spatial cross in parallel projection. Rotation of three-dimensional objects on all three axes at once.

Your browser does not support Canvas

Spatial cross

Your browser does not support Canvas

Cross-cube
The algorithm is universal and very simple: take three-dimensional matrix and build the cubes by its points. Join the cubes in a single figure and start a rotation. The matrix may be different - the essence remains the same. For this example I took two variants of the spatial cross.1. Matrix - spatial cross (y, x, z)
JavaScript
// Figure
let figure = {
    shape: [
        [[0,0,0,0,0], [0,0,0,0,0], [0,0,1,0,0], [0,0,0,0,0], [0,0,0,0,0]],
        [[0,0,0,0,0], [0,0,0,0,0], [0,0,1,0,0], [0,0,0,0,0], [0,0,0,0,0]],
        [[0,0,1,0,0], [0,0,1,0,0], [1,1,1,1,1], [0,0,1,0,0], [0,0,1,0,0]],
        [[0,0,0,0,0], [0,0,0,0,0], [0,0,1,0,0], [0,0,0,0,0], [0,0,0,0,0]],
        [[0,0,0,0,0], [0,0,0,0,0], [0,0,1,0,0], [0,0,0,0,0], [0,0,0,0,0]]
    ]
};

// Center of the figure.
// We'll make a turn around it
let t0 = {
    y:figure.shape.length / 2 * size,
    x:figure.shape[0].length / 2 * size,
    z:figure.shape[0][0].length / 2 * size
};
2. Launch the loop through the matrix (three-dimensional array), which builds cubes for each non-zero point.
JavaScript
for (let y = 0; y < figure.shape.length; y++) {
    for (let x = 0; x < figure.shape[0].length; x++) {
        for (let z = 0; z < figure.shape[0][0].length; z++) {
            ...
            // Build a cube as array of 6 faces
            ...
        }
    }
}
3. Build each cube as array of 6 faces. For example, take the left face. If there is another cube to the left of it, then don't draw this face, in order to avoid intermediate faces inside the figure - the corresponding face of another cube don't draw too. All other faces are build similar way.
JavaScript
// Size of the cube
let size = 30;

// Left face
face = [
    {x:x*size, y:y*size, z:z*size},
    {x:x*size, y:y*size, z:z*size + size},
    {x:x*size, y:y*size + size, z:z*size + size},
    {x:x*size, y:y*size + size, z:z*size},
];

// Central coordinate,
// it is needed to calculate the distance from axes (X) and (Z)
face[4] = getFaceCentralCoordinate(face);

// If there is something to the left, then do not draw this face
if (x > 0 && figure.shape[y][x - 1][z] === 1) {
    face[5] = {display:false};
}
Now we have three-dimensional object, which consist of cubes, which consist of faces which consist of points. Start the rotation - now at each step first rotate the figure by the angle, then make two-dimensional projection and in the end draw the projection on the screen. Don't draw three-dimensional hologram.4. Launch the loop through all points of which the object consists and turn each of them by an angle on each axis. For example, take the rotation on axis (Y). Rotation on axis (X) and (Z) performs similarly.
JavaScript
// Turn point t(x,y,z) by an angle (deg) on axis (Y)
// relative to the point t0(x,y,z)
function rotateByDegreeY(t0, t) {

    let t_new = {};

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

    // Calculate coordinates of new point according to 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 resulting value
    return t_new;
}
Now the projection of the resulting figure needs to be made. There are only two variants: parallel projection and perspective projection. The difference between them we discussed in a previous article: Rotate the cube in space. For the current example, I chose a parallel projection.
5. Build a parallel projection for each point of the figure.
JavaScript
// Parallel projection of a point
function getPointParallelProjection(point) {
    return {
        x:point.x,
        y:point.y + point.z / 4};
}
6. Work with projection. Draw each projection of the face of the figure by the points of which it consists.
JavaScript
// Draw a figure through points from an array
function fillFigure(canvas_context, arr) {
    canvas_context.lineWidth = 2;
    canvas_context.strokeStyle = 'rgba(250,250,100,0.3)';

    for (let i = 0; i < arr.length; i++) {
        if (arr[i].length < 5) {
            canvas_context.beginPath();
            if (i < 3) {
                canvas_context.fillStyle = 'rgba(0,200,0,0.9)';
            } else {
                canvas_context.fillStyle = 'rgba(0,200,0,0.5)';
            }
            for (let j = 0; j < arr[i].length; j++) {
                if (j === 0) {
                    canvas_context.moveTo(arr[i][j].x, arr[i][j].y);
                } else {
                    canvas_context.lineTo(arr[i][j].x, arr[i][j].y);
                }
            }
            canvas_context.closePath();
            canvas_context.fill();
            canvas_context.stroke();
        }
    }
}
There were major steps of the algorithm. I hope it became clear how it works.
Privacy policy
Back to Top