ГлавнаяИгрыБлогКонтакты

RUEN
{{item}}
Вращаем куб в пространстве. Canvas

05.08.2017
HTML5, CanvasСмотреть код
Рассматриваем разницу между параллельной и перспективной проекцией. Обе широко используются на практике для различных целей.
В предыдущемпримеремы вращали квадрат на плоскости. Переходим в трехмерное пространство. Теперь, чтобы отобразить на плоскости экрана движение трехмерного объекта, нужно сначала создать трехмерный объект, повернуть его на угол, срисовать с него проекцию и отобразить на экране уже проекцию.

Ваш браузер не поддерживает Canvas

Параллельная проекцияВид проекции, которая образуется с помощью параллельных проецирующих лучей.

Ваш браузер не поддерживает Canvas

Перспективная проекцияВид проекции, которая образуется с помощью проецирующих лучей, исходящих из одной точки.
У этой статьи есть продолжение:Вращаем пространственный крест
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! В дополнение приведу поворот по всем трем осям сразу.
Параллельная проекция

Ваш браузер не поддерживает Canvas

Перспективная проекция

Ваш браузер не поддерживает Canvas

Комментарии
O0O0O0O0Комментатор01.01.1970 03:00 (MSK)
Комментариев пока нет.. Вы можете стать первым..
Политика конфиденциальности
Введите ваше имя
Введите ваш e-mail
Введите ваше сообщение
Отправить
captcha