Введение в минималистичную 3D-графику
Забыли, как работают тяжелые движки вроде Unreal или Blender, когда под рукой всего один HTML5 Canvas и чистый JavaScript? Прямо сейчас, когда веб-приложения обрастают гигабайтами зависимостей ради простой кнопки, понимание фундаментального кода становится главным скиллом инженера. Представьте: вы настраиваете свой портфолио или прототипируете интерактивный редактор интерьеров для заказчика, где каждая библиотека третья сторона замедляет загрузку. Написание компактного, но полноценного 3D-моделлера позволяет отбросить избыточные абстракции и сосредоточиться на фундаментальных вещах: матричных преобразованиях, проекции пространства, обработке пользовательского ввода и базовом растеризаторе.
В мире разработки ключевой принцип остается неизменным: максимум функциональности при минимальном объеме кода. Тот же подход к оптимизации применим и к написанию графических утилит.
Цель этой статьи — разобрать устройство учебного 3D-моделлера, который укладывается всего в 500 строк кода, работает прямо в браузере и демонстрирует, как устроен конвейер трехмерной графики изнутри.
Математический фундамент и векторная алгебра
От концепта виртуальной комнаты до первых пикселей на экране лежит пропасть из формул, но перешагнуть её проще, чем кажется. Любой 3D-моделлер начинается с линейной алгебры. Чтобы оперировать трехмерными объектами на двумерном экране монитора, нам необходим базовый набор математических структур: векторы (Vector3) и матрицы (Matrix4x4). Без сторонних библиотек вроде GLM или Three.js нам придется реализовать их самостоятельно.
Вектор в трехмерном пространстве задается тремя координатами (x, y, z). Над ними должны быть определены стандартные операции:
- Сложение и вычитание векторов
- Умножение вектора на скаляр
- Скалярное и векторное произведения
- Нормализация (приведение длины к единице)
Для работы с матрицами преобразований нам понадобится матрица размером 4х4, поддерживающая операции трансляции (перемещения), масштабирования и вращения по трем осям (Pitch, Yaw, Roll), а также перспективную проекцию.
Пример реализации базового класса для работы с точками на JavaScript выглядит следующим образом:
class Vector3 {
constructor(x = 0, y = 0, z = 0) {
this.x = x;
this.y = y;
this.z = z;
}
add(v) {
return new Vector3(this.x + v.x, this.y + v.y, this.z + v.z);
}
multiplyScalar(s) {
return new Vector3(this.x * s, this.y * s, this.z * s);
}
}
Проекция и графический конвейер
Имея на руках математический базис, мы готовы оживить наши данные и превратить абстрактные цифры в осязаемые формы сцены. Классический мини-моделлер оперирует примитивами: вершинами (vertices), ребрами (edges) и полигонами (faces). Наша задача — взять массив точек в мировых координатах и спроецировать их на экранную плоскость.
Графический конвейер в таком приложении состоит из нескольких последовательных шагов:
- Локальные координаты: вершины объекта задаются относительно его собственного центра.
- Мировые преобразования: объект перемещается, вращается и масштабируется в общем виртуальном пространстве сцены.
- Видовое преобразование (Camera View): сцена пересчитывается относительно позиции и направления взгляда виртуальной камеры.
- Проекция (Projection): трехмерные координаты трансформируются в двумерные с учетом перспективы.
- Растеризация: отрисовка линий и полигонов на холсте (Canvas).
На этапе растеризации критически важна производительность. Код должен эффективно пересчитывать тысячи полигонов в реальном времени, сохраняя стабильный фреймрейт в 60 кадров в секунду.
Интерфейс и обработка пользовательского ввода
Статичная картинка — это скучно, поэтому следующий шаг заставляет наш мини-мир реагировать на каждое движение пользователя. Интерактивность — ключевой элемент любого моделлера. Нам нужно отслеживать события перемещения мыши (mousemove) и нажатия кнопок (mousedown, mouseup), чтобы изменять углы поворота камеры или выбранного объекта.
В минималистичной архитектуре обработка ввода сводится к простому автомату состояний:
- Флаг
isDraggingпереключается в true при зажатой левой кнопке мыши. - Разница между текущим и предыдущим положением курсора преобразуется в угловую скорость вращения сцены.
- Колесико мыши (wheel event) отвечает за зум (приближение/удаление), меняя коэффициент масштабирования в матрице проекции.
Реализация каркасного (Wireframe) рендерера
Связав воедино математику и реакцию на мышь, мы подходим к самому зрелищному этапу — зарисовке геометрии на холст. Полноценный пиксельный рендеринг с текстурами и освещением по Фонгу занял бы слишком много места. Поэтому в концепции «500 Lines or Less» используется каркасный (wireframe) рендеринг. Мы рисуем только ребра объектов, соединяющие вершины.
Для реализации рендерера нам понадобится стандартный 2D Context HTML5 Canvas. Алгоритм отрисовки кадра:
- Очистить экран (залить холст фоновым цветом).
- Пройти циклом по всем объектам сцены.
- Применить матрицу трансформации к массиву вершин.
- Выполнить перспективную проекцию полученных 3D-точек в 2D-координаты экрана.
- Соединить вершины линиями с помощью метода
ctx.lineTo().
Ниже представлен фрагмент кода, отвечающий за отрисовку ребер на холсте:
function renderWireframe(ctx, transformedVertices, edges, width, height) {
ctx.clearRect(0, 0, width, height);
ctx.strokeStyle = '#00ff00';
ctx.lineWidth = 1.5;
for (let edge of edges) {
let p1 = transformedVertices[edge[0]];
let p2 = transformedVertices[edge[1]];
let x1 = p1.x + width / 2;
let y1 = -p1.y + height / 2;
let x2 = p2.x + width / 2;
let y2 = -p2.y + height / 2;
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.stroke();
}
}
Заключение
Создание 3D-моделлера в рамках 500 строк кода — это прекрасное упражнение для разработчика, желающего глубоко понять внутреннее устройство компьютерной графики. Мы убедились, что за сложными трехмерными эффектами в современных приложениях стоят базовые принципы линейной алгебры и матричного умножения.
Минималистичный код не только учит нас эффективному использованию ресурсов, но и доказывает, что для создания работающего прототипа сложного ПО не нужны гигантские зависимости. Главное — четкое понимание архитектуры и математической основы проекта. Откройте редактор кода, соберите этот пайплайн своими руками и заставьте трехмерный куб вращаться прямо в браузере уже сегодня!