cherry.png

Rotate the cube in space. Canvas

05.08.2017
checkmark3

HTML5, Canvas

Consider the difference between parallel and perspective projection. Both are widely used in practice for different purposes.
In the previousexamplewe have rotated square on the plane. Now go 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 to the corner, draw its projection and display on the screen the projection.

Your browser does not support Canvas

Parallel projection

The type of projection, which produced by parallel projecting rays.

Your browser does not support Canvas

Perspective projection

The type of projection, which produced by projecting rays, outgoing from a single point.
This article has continuation:Spinning spatial cross

JavaScript

    'use strict';

    // Рисовать будем сразу две картинки,
    // объект у нас будет один, а проеций будет много
    var canvas1 = document.getElementById('canvas1');
    var canvas2 = document.getElementById('canvas2');

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

    // Сместим начало координат в центр блока
    canvas_context1.translate(canvas1.width / 2, canvas1.height / 2);
    canvas_context2.translate(canvas2.width / 2, canvas2.height / 2);
    // Фигуру будем задавать как совокупность четырех плоскостей,
    // каждая плоскость - совокупность четырех точек
    var arr_t = [
    // Передняя стенка
    [{x:-100, y:-100, z:-100},
        {x:100, y:-100, z:-100},
        {x:100, y:100, z:-100},
        {x:-100, y:100, z:-100}],
    // Правая стенка
    [{x:100, y:-100, z:-100},
        {x:100, y:-100, z:100},
        {x:100, y:100, z:100},
        {x:100, y:100, z:-100}],
    // Левая стенка
    [{x:-100, y:-100, z:-100},
        {x:-100, y:-100, z:100},
        {x:-100, y:100, z:100},
        {x:-100, y:100, z:-100}],
    // Задняя стенка
    [{x:-100, y:-100, z:100},
        {x:100, y:-100, z:100},
        {x:100, y:100, z:100},
        {x:-100, y:100, z:100}]];
    // Центр фигуры.
    // Вокуг него будем осуществлять поворот
    var t0 = {x:0, y:0, z:0};

    // Угол поворота в градусах
    var deg = 0;

    // Для перспективной проекции:
    // Удаленность наблюдателя от объекта.
    // Не может быть меньше размеров объекта,
    // в нашем случае 200px
    var a = 300;

    // Размер объекта на экране в (%)
    var k = 70;

    // Текущая фигура
    var arr_tt = [];
    for (var i = 0; i < arr_t.length; i++) {
        arr_tt[i] = arr_t[i].slice();
    }

    // Текущая проекция
    var arrProj;
    // Задаем функцию обновления отображения
    // с поворотом фигуры.
    // Затем эту функцию надо будет вставить
    // в переменную window.onload
    function repaint() {

        // Сначала очистим экран - закрасим белым цветом
        clearScreen(canvas1, canvas_context1, 'rgb(255,255,255)');
        clearScreen(canvas2, canvas_context2, 'rgb(255,255,255)');

        // Теперь повернем исходную фигуру на угол
        // по оси Y и перезапишем текущую фигуру
        for (var i = 0; i < arr_t.length; i++) {
            for (var j = 0; j < arr_t[0].length; j++) {
                arr_tt[i][j] = rotateOnDegreeY(t0, arr_t[i][j], deg);
            }
        }

        // Получим параллельную проекцию
        arrProj = getParallelProjection(arr_tt);

        // Нарисуем ее
        canvas_context1.lineWidth = 2; // черный полупрозрачный
        strokeFigure(canvas_context1, arrProj, 'rgba(0,0,0,0.5)');

        // Получим перспективную проекцию
        arrProj = getPerspectiveProjection(arr_tt);

        // Нарисуем ее тоже в соседнем окошке
        canvas_context2.lineWidth = 2; // черный полупрозрачный
        strokeFigure(canvas_context2, arrProj, 'rgba(0,0,0,0.5)');

        // Увеличиваем угол
        deg += 1;
    }
    // Далее идут вспомогательные функции

    // Получаем параллельную проекцию фигуры на плоскость экрана
    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;
    }
    // Получаем перспективную проекцию
    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;
    }
    // Закрашиваем весь экран определенным цветом
    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();
    }

    // Рисуем фигру по точкам из массива
    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();
        }
    }
    // Поворачиваем точку t(x,y,z) на угол (deg) по оси (Y)
    // относительно точки t0(x,y,z)
    function rotateOnDegreeY(t0, t, deg) {

        var t_new = {};

        // Переводим угол поворота из градусов в радианы
        var rad = (Math.PI / 180) * deg;

        // Рассчитываем координаты новой точки по формуле
        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 t_new;
    }

    // Устанавливаем интервал обновления отображения
    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


facebookvkontaktetwitterodnoklassnikimailrulivejournal

Comments

O0O0O0O0
Commentator
01.01.1970 03:00 (MSK)
There are no comments yet.. You can be the first..