three.js: 3D-графика в браузере — от сцены до анимации
Знакомая сцена. Вы захотели добавить на сайт что-то трёхмерное: вращающуюся модель товара, интерактивный глобус, объёмный фон для портфолио. Открываете документацию по WebGL — родной браузерный способ рисовать 3D — и видите сотни строк ради одного треугольника. Шейдеры на отдельном языке, буферы вершин, матрицы преобразований, ручная привязка атрибутов. День работы — и на экране один треугольник.
Проблема не в том, что вы чего-то не знаете. WebGL — это низкий уровень, разговор с видеокартой почти напрямую. Он мощный, но требует описывать руками каждую мелочь, которую в трёхмерной графике хочется получить готовой: камеру, свет, материалы, тени.
three.js закрывает этот разрыв. Это библиотека на JavaScript поверх WebGL: вы думаете не матрицами и буферами, а понятными вещами — сцена, камера, объект, свет. Несколько десятков строк — и в браузере крутится освещённый куб с тенями. То, что на голом WebGL заняло бы сотни строк, здесь умещается в одну страницу кода.
Разберём по шагам: три обязательных объекта любой сцены, из чего собран трёхмерный объект, как работают камеры и свет, что такое цикл анимации. В конце соберём вращающуюся освещённую фигуру с нуля.
three.js строится на JavaScript — язык и устройство фронтенда разбирают в программе «Фронтенд-разработчик» на Хекслете.
Что такое three.js
three.js — самая популярная библиотека для трёхмерной графики в вебе. Её задача — спрятать сложность WebGL за понятными объектами. Вместо того чтобы вручную считать, как куб проецируется на экран под нужным углом, вы создаёте куб, ставите камеру и говорите «нарисуй». Математику проекций, работу с видеокартой и тонкости WebGL библиотека берёт на себя.
Где это применяют: трёхмерные витрины товаров с вращением и зумом, конфигураторы (собери свою машину или кроссовок), визуализация данных в объёме, презентации и фоны на сайтах, простые браузерные игры, архитектурные и медицинские модели. Везде, где в браузере нужен объём, а не плоская картинка.
Важно понимать границу. three.js — не игровой движок вроде Unity со встроенным редактором, физикой и звуком. Это библиотека отрисовки: она про то, как показать трёхмерную сцену. Физику, звук, игровую логику добавляют отдельно. Зато three.js лёгкая, работает в любом современном браузере без установки и отлично дружит с обычным фронтендом.
Ещё одна причина популярности — экосистема. Вокруг three.js собрана огромная коллекция готовых дополнений: загрузчики моделей разных форматов, управление камерой, постобработка с эффектами вроде свечения и размытия, помощники для отладки сцены. Документация богата живыми примерами, которые можно открыть и сразу покрутить. А обёртка react-three-fiber встраивает трёхмерную сцену в привычные React-компоненты. Всё это означает, что типовую задачу почти всегда удаётся собрать из готовых частей, не изобретая велосипед.
Три объекта, без которых ничего не появится
Любая сцена three.js держится на трёх объектах. Удобно представить их как съёмочную площадку.
Объект | Аналогия | За что отвечает |
|---|---|---|
Scene | Съёмочная площадка | Контейнер для всего: объектов, света, фона |
Camera | Камера оператора | Откуда и под каким углом мы смотрим на сцену |
Renderer | Экран и проектор | Берёт сцену глазами камеры и выводит картинку на canvas |

Логика простая: на площадку (scene) ставят объекты и свет, оператор (camera) выбирает точку обзора, а проектор (renderer) превращает всё это в плоскую картинку на странице. Уберёшь любой из трёх — на экране ничего не будет. Это скелет, на который дальше навешивается всё остальное.
Первая сцена: освещённый куб
Соберём минимальную рабочую сцену. Подключаем библиотеку и создаём три обязательных объекта:
import * as THREE from 'three';
// 1. Сцена — контейнер для всего
const scene = new THREE.Scene();
// 2. Камера — откуда смотрим
const camera = new THREE.PerspectiveCamera(
75, // угол обзора в градусах
window.innerWidth / window.innerHeight, // соотношение сторон
0.1, 1000 // ближняя и дальняя границы видимости
);
camera.position.z = 5;
// 3. Renderer — выводит картинку на canvas
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);Теперь добавим объект. В three.js объект — это всегда месь (mesh): сочетание формы и поверхности. И свет, иначе объект останется чёрным:
// Объект = форма (geometry) + поверхность (material)
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshStandardMaterial({ color: 0x2d2adf });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
// Свет — без него материал MeshStandard выглядит чёрным
const light = new THREE.DirectionalLight(0xffffff, 2);
light.position.set(2, 2, 5);
scene.add(light);
// Выводим один кадр
renderer.render(scene, camera);Этого хватит, чтобы на экране появился синий куб. Дальше его можно вращать, двигать камеру, добавлять объекты — но скелет уже стоит.
Mesh: форма плюс поверхность
Видимый объект в three.js всегда состоит из двух частей. Geometry задаёт форму — координаты вершин и граней. Material задаёт поверхность — цвет, блеск, прозрачность, текстуру. Соединённые вместе через Mesh, они и дают то, что видно на экране.

Готовых форм много, и под типовые задачи не нужно ничего считать руками:
Geometry | Форма |
|---|---|
| Куб и параллелепипед |
| Сфера |
| Плоскость — пол, стена, экран |
| Цилиндр и конус |
| Тор — бублик, кольцо |
Материалы отличаются тем, как они реагируют на свет:
Material | Поведение |
|---|---|
| Сплошной цвет, свет игнорирует — виден всегда |
| Реалистично реагирует на свет, есть металличность и шероховатость |
| Блики и глянец, легче стандартного |
Чёрный объект на экране — почти всегда нет света. Материалы, которые реагируют на освещение (Standard, Phong, Physical), без источника света выглядят чёрными — освещать их нечем. Либо добавьте свет на сцену, либо для простых задач возьмите MeshBasicMaterial, которому свет не нужен. Это первая ошибка, на которую натыкаются почти все новички.
Координаты, поворот, масштаб
Каждый объект на сцене живёт в трёхмерном пространстве с тремя осями: X — влево-вправо, Y — вверх-вниз, Z — к нам и от нас. Управляют объектом через три свойства, и они есть у любого меша, камеры и света.
Свойство | Что меняет |
|---|---|
| Где объект стоит — сдвиг по X, Y, Z |
| Как повёрнут — углы вокруг каждой оси |
| Размер — растяжение по каждой оси |
cube.position.set(2, 0, -3); // сдвинуть вправо и вглубь
cube.rotation.y = Math.PI / 4; // повернуть на 45° вокруг вертикали
cube.scale.set(2, 1, 1); // растянуть вдвое по горизонталиУглы поворота задаются в радианах, а не градусах: полный круг — это 2 * Math.PI, прямой угол — Math.PI / 2. Это частый источник путаницы у новичков — поставили rotation.y = 90, ожидая четверть оборота, а объект провернулся пятнадцать раз. Девяносто градусов — это Math.PI / 2.
Эти же три свойства и оживляют сцену в цикле анимации: меняешь position кадр за кадром — объект едет, меняешь rotation — крутится. Вся анимация в three.js по сути сводится к тому, чтобы аккуратно менять координаты, поворот и масштаб между кадрами.
Камеры: перспектива и ортография
Камера решает, как трёхмерная сцена ложится на плоский экран. В three.js два основных типа, и выбор между ними меняет всю картинку.
Камера | Как видит | Когда брать |
|---|---|---|
| С перспективой: дальние объекты мельче, как видит глаз | Почти всегда — реалистичные сцены, витрины, игры |
| Без перспективы: размер не зависит от расстояния | Изометрия, чертежи, 2.5D-игры, схемы |
Перспективная камера задаётся четырьмя числами: угол обзора, соотношение сторон и две границы видимости — ближняя и дальняя. Всё, что ближе ближней границы или дальше дальней, не рисуется. Эта область в форме усечённой пирамиды называется пирамидой видимости: камера видит только то, что попало внутрь.

Ортографическая камера рисует объекты одинакового размера независимо от того, далеко они или близко. Так строят изометрические игры и технические чертежи, где важны точные пропорции, а не глубина. Для большинства задач берут перспективную — она привычнее глазу.
Свет: четыре источника
Без света трёхмерная сцена — это плоские силуэты. Свет создаёт объём: подсвечивает одни грани, затеняет другие, рисует блики. В three.js несколько типов источников, и каждый светит по-своему.

Свет | Как светит | Аналогия |
|---|---|---|
| Равномерно подсвечивает всё, без направления и теней | Рассеянный свет пасмурного дня |
| Параллельные лучи в одном направлении | Солнце |
| Из точки во все стороны, гаснет с расстоянием | Лампочка |
| Конусом в заданном направлении | Прожектор, фонарик |
На практике свет комбинируют. Частый приём: немного AmbientLight, чтобы тени не были совсем чёрными, плюс DirectionalLight как основной источник для объёма и теней. Так сцена выглядит естественно и не уходит в темноту.
Цикл анимации: как картинка оживает
Пока мы вызывали отрисовку один раз — получали застывший кадр. Чтобы объект двигался, кадры нужно перерисовывать снова и снова, чуть меняя сцену между ними. Это и есть цикл анимации.

Главный инструмент — функция requestAnimationFrame. Она просит браузер вызвать вашу функцию перед следующей перерисовкой экрана, обычно около 60 раз в секунду. Внутри вы меняете объекты и выводите новый кадр:
function animate() {
requestAnimationFrame(animate); // запланировать следующий кадр
cube.rotation.x += 0.01; // чуть повернуть куб
cube.rotation.y += 0.01;
renderer.render(scene, camera); // нарисовать кадр заново
}
animate();Логика такая: меняем сцену на капельку, рисуем кадр, просим следующий — и так по кругу, пока открыта страница. Поскольку requestAnimationFrame подстраивается под частоту экрана, движение получается плавным и не тратит ресурсы, когда вкладка неактивна.
Не создавайте объекты внутри цикла анимации. Если каждый кадр создавать новую геометрию или материал, за секунду набегают десятки лишних объектов — память течёт, сцена тормозит. Геометрию, материалы и меши создают один раз до цикла, а внутри только меняют их свойства: поворот, положение, цвет.
Управление мышью и загрузка моделей
Две вещи, без которых редко обходится реальная сцена.
OrbitControls даёт пользователю вращать сцену мышью, приближать и двигать камеру. Это то самое поведение трёхмерных витрин — схватил мышкой и покрутил товар. Подключается несколькими строками:
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
const controls = new OrbitControls(camera, renderer.domElement);
// в цикле анимации добавить:
controls.update();Загрузка моделей. Собирать сложные объекты из кубов и сфер непрактично — их делают в редакторах вроде Blender и сохраняют в формате glTF. three.js загружает такие модели готовыми, со всеми материалами и анимацией:
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
const loader = new GLTFLoader();
loader.load('model.glb', (gltf) => {
scene.add(gltf.scene);
});Текстуры — картинки на поверхности объектов — подключают похожим способом через TextureLoader: загрузили изображение, повесили на материал. Так дерево становится деревянным, а планета — узнаваемой Землёй.
Практика: вращающаяся фигура с нуля
Соберём то, ради чего обычно и приходят к three.js, — освещённую фигуру, которая крутится. Полный код умещается в один файл.
import * as THREE from 'three';
// 1. Три обязательных объекта
const scene = new THREE.Scene();
scene.background = new THREE.Color(0xf4f4f4);
const camera = new THREE.PerspectiveCamera(
75, window.innerWidth / window.innerHeight, 0.1, 1000
);
camera.position.z = 4;
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 2. Объект: форма + материал (создаём один раз)
const geometry = new THREE.TorusKnotGeometry(0.8, 0.3, 100, 16);
const material = new THREE.MeshStandardMaterial({
color: 0x2d2adf, roughness: 0.3, metalness: 0.6
});
const shape = new THREE.Mesh(geometry, material);
scene.add(shape);
// 3. Свет: рассеянный + направленный
scene.add(new THREE.AmbientLight(0xffffff, 0.4));
const dir = new THREE.DirectionalLight(0xffffff, 2);
dir.position.set(3, 3, 5);
scene.add(dir);
// 4. Цикл анимации
function animate() {
requestAnimationFrame(animate);
shape.rotation.x += 0.01;
shape.rotation.y += 0.01;
renderer.render(scene, camera);
}
animate();Тридцать строк — и в браузере крутится блестящий узел с реалистичным освещением. Добавьте OrbitControls — и фигуру можно будет вращать мышью. Поменяйте геометрию на SphereGeometry или загрузите свою модель — каркас сцены остаётся тем же. Вот ради чего стоило не уходить в дебри WebGL.
Производительность и частые ошибки
Создавать геометрию и материалы в цикле анимации. Самая частая причина утечек памяти и тормозов. Всё, что не меняется, создают один раз до цикла. Внутри только обновляют свойства существующих объектов.
Забывать про свет со Standard-материалами. Объект чёрный, и кажется, что он не загрузился. На деле его просто нечем осветить. Либо свет, либо MeshBasicMaterial.
Не обрабатывать изменение размера окна. Пользователь повернул телефон или растянул окно — картинка искажается. При изменении размера нужно обновить соотношение сторон камеры и размер renderer, иначе пропорции поплывут.
Не освобождать память удалённых объектов. Просто убрать меш со сцены мало — геометрия и материал остаются в памяти видеокарты. У них есть метод dispose(), который освобождает ресурсы. На долгоживущих сценах это важно.
Тяжёлые модели без оптимизации. Модель на миллионы полигонов положит даже мощную машину. Перед загрузкой модели упрощают в редакторе, а большие сцоны собирают из повторяющихся объектов с переиспользованием геометрии.
FAQ
Нужно ли знать WebGL, чтобы начать с three.js?
Нет. Смысл three.js как раз в том, чтобы не трогать WebGL напрямую. Достаточно знать JavaScript и понимать базовые объекты: сцена, камера, объект, свет. WebGL пригодится позже, если захотите писать свои шейдеры для нестандартных эффектов.
Сколько математики нужно?
На старте — минимум. Координаты по трём осям и углы поворота поймёт любой. Векторы и матрицы полезны для сложных сцен и анимаций, но библиотека прячет большую часть вычислений. Начать можно без них и подтягивать по мере роста задач.
three.js подходит для игр?
Для несложных браузерных игр — да. Но three.js отвечает только за графику: физику, звук, игровую логику и редактор уровней придётся добавлять отдельно или брать готовые библиотеки. Для серьёзных игр чаще берут полноценный движок вроде Unity или Godot.
Как three.js дружит с React и Vue?
Хорошо. Для React есть обёртка react-three-fiber, которая описывает сцену в привычных компонентах. С Vue и другими фреймворками three.js работает напрямую — отрисовку запускают в нужный момент жизненного цикла компонента. Трёхмерная сцена спокойно живёт внутри обычного интерфейса.
Будет ли это работать на телефонах?
Да, WebGL поддерживают все современные мобильные браузеры. Но у телефонов слабее видеокарта, поэтому сцены делают легче: меньше полигонов, проще свет, аккуратнее с тенями. Хорошая практика — проверять сцену на реальном телефоне, а не только на мощном компьютере.
Чем three.js отличается от Babylon.js?
Обе — библиотеки 3D для браузера. three.js легче, гибче и популярнее, вокруг неё огромное сообщество и масса примеров. Babylon.js ближе к игровому движку: больше встроенного из коробки — физика, инструменты, редактор. Для веб-графики и эффектов чаще берут three.js, для игровых проектов присматриваются к Babylon.






