Создание интерактивного гиперкуба: эксперименты с трёхмерной графикой и выход в четвёртое измерение

cc2417cf5ae2493fe6aa276060d76857

Каждый раз, когда я сталкиваюсь с чем-то новым в разработке графики, я задаюсь вопросом: «А можно ли сделать что-то круче?» Создавать трёхмерные сцены в браузере — задача увлекательная, но уже привычная. Мы привыкли работать с кубами, сферами и прочими объектами в 3D-пространстве. Но что, если выйти за его пределы? А что, если ввести в игру четвёртое измерение? Именно эта мысль и привела меня к созданию интерактивного гиперкуба с помощью Three.js.

Почему гиперкуб?

Возможно, вам знакома идея гиперкуба, или тессеракта — четырехмерного аналога обычного куба. В отличие от простого куба, тессеракт содержит в себе дополнительную «глубину» — измерение, которое сложно визуализировать в реальном мире, но с помощью математики и графики его можно показать в проекции на трёхмерное пространство. Казалось бы, задача понятна, но как же подступиться к ней? В этой статье я хочу рассказать, как сделать интерактивную визуализацию гиперкуба, который вращается, меняет цвет и даже подстраивается под действия пользователя.

Интрига: как мы вообще будем рисовать объект с четырьмя измерениями в трёхмерном пространстве? Ответ, как всегда, прост и сложен одновременно — проекции. Но обо всём по порядку.

Начало: куб как точка входа

Первое, с чего мы начнём — это создание простого куба. Если вы уже работали с Three.js, то для вас это не будет чем-то новым. Мы создадим сцену, камеру, настроим рендер и добавим куб, который будет динамично вращаться.

Вот код, который рисует стандартный куб:

const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();

renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

// Создание куба с рёбрами
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.LineBasicMaterial({ color: 0x00ff00 });
const edges = new THREE.EdgesGeometry(geometry);
const line = new THREE.LineSegments(edges, material);

scene.add(line);
camera.position.z = 5;

Здесь мы создали обычный трёхмерный куб с зелёными рёбрами и камерой, которая находится на небольшом удалении от объекта. Это базовый уровень, но уже интерактивный. Я добавил возможность изменять цвет куба с помощью цветового инпута:

Но как быть с четвёртым измерением?

Здесь начинается самое интересное. Как вообще можно отобразить объект в четырёхмерном пространстве на экране?

Теория в действии

Представьте, как вы проецируете трёхмерный куб на двумерную поверхность (например, лист бумаги). Мы видим его тени и проекции, и по этим двумерным проекциям можем восстановить трёхмерный объект. Так же и с тессерактом — мы можем показать его «тени», спроецировав его на трёхмерное пространство, доступное для нашего восприятия.

Для этого нужно воспользоваться проекцией 4D-координат на 3D, чтобы рёбра и вершины гиперкуба можно было отобразить. Сначала нам нужно описать вершины гиперкуба:

const vertices = [
    new THREE.Vector4(-1, -1, -1, -1),
    new THREE.Vector4(1, -1, -1, -1),
    new THREE.Vector4(1, 1, -1, -1),
    new THREE.Vector4(-1, 1, -1, -1),
    new THREE.Vector4(-1, -1, 1, -1),
    new THREE.Vector4(1, -1, 1, -1),
    new THREE.Vector4(1, 1, 1, -1),
    new THREE.Vector4(-1, 1, 1, -1),
    new THREE.Vector4(-1, -1, -1, 1),
    new THREE.Vector4(1, -1, -1, 1),
    new THREE.Vector4(1, 1, -1, 1),
    new THREE.Vector4(-1, 1, -1, 1),
    new THREE.Vector4(-1, -1, 1, 1),
    new THREE.Vector4(1, -1, 1, 1),
    new THREE.Vector4(1, 1, 1, 1),
    new THREE.Vector4(-1, 1, 1, 1)
];

Но для тессеракта недостаточно просто нарисовать эти вершины. Мы должны соединить их рёбрами:

const edges = [
    [0, 1], [1, 2], [2, 3], [3, 0],
    [4, 5], [5, 6], [6, 7], [7, 4],
    [0, 4], [1, 5], [2, 6], [3, 7],
    [8, 9], [9, 10], [10, 11], [11, 8],
    [12, 13], [13, 14], [14, 15], [15, 12],
    [8, 12], [9, 13], [10, 14], [11, 15],
    [0, 8], [1, 9], [2, 10], [3, 11],
    [4, 12], [5, 13], [6, 14], [7, 15]
];

Каждое ребро соединяет две вершины — это основа для построения каркаса тессеракта.

Проблема: рендеринг и восприятие

Одной из самых больших проблем при визуализации многомерных объектов является то, что наш мозг не способен «видеть» четвертое измерение. Но здесь на помощь приходят повороты и анимация. Мы можем показать гиперкуб в разных проекциях, вращая его по разным осям, что создаёт иллюзию дополнительного измерения.

Функция для создания рёбер гиперкуба с использованием BufferGeometry:

function createTesseractEdges() {
    const edges = [];
    for (const [start, end] of edgeIndices) {
        edges.push(vertices[start], vertices[end]);
    }
    const geometry = new THREE.BufferGeometry().setFromPoints(edges);
    return geometry;
}

Когда пользователь выбирает тессеракт вместо обычного куба, мы просто меняем геометрию объекта:

shapeSelector.addEventListener('change', (event) => {
    currentShape = event.target.value;
    if (currentShape === "cube") {
        line.geometry = new THREE.EdgesGeometry(new THREE.BoxGeometry(1, 1, 1));
    } else if (currentShape === "tesseract") {
        line.geometry = createTesseractEdges();
    }
});

Управляем вращением и цветом

Куб или тессеракт вращаются автоматически, но мы также можем управлять скоростью вращения с помощью ползунка:

const rotationSpeedSlider = document.getElementById('rotationSpeed');
rotationSpeedSlider.addEventListener('input', (event) => {
    rotationSpeed = parseFloat(event.target.value);
});

Это делает объект более интерактивным: пользователи могут как менять скорость вращения, так и останавливать объект кликом мыши.

Что дальше?

Поработав над тессерактом, я осознал, что границы, по сути, не существуют. Многомерные объекты могут быть визуализированы, если уметь их правильно «проецировать» на наши привычные три измерения. Следующим шагом станет визуализация пенторакта (пятимерного гиперкуба), а может, и объектов с ещё большими измерениями.

Если вы хотите повторить этот эксперимент или доработать его под свои нужды, код доступен на моём GitHub, и, конечно же, буду рад вашим вопросам и предложениям.

Итог

Этот небольшой проект — прекрасный пример того, как с помощью простых инструментов вроде Three.js можно визуализировать сложные математические объекты и создавать интерактивные приложения, которые выходят за рамки привычного 3D-пространства. Гиперкубы и многомерные фигуры перестают быть абстракцией и превращаются в наглядные и понятные структуры, которые можно изучать, вращать и настраивать. Это не только расширяет границы нашего воображения, но и открывает путь к более глубокому пониманию математических и физических концепций, которые раньше казались недосягаемыми.

© Habrahabr.ru