Создание 3D-сайтов на WebGL: от основ до публикации проекта
Для кого эта статья:
- Студенты и начинающие веб-разработчики
- Профессиональные разработчики, интересующиеся 3D-графикой
Дизайнеры и специалисты по UX/UI, желающие интегрировать 3D-элементы в свои проекты
3D-графика на веб-страницах перестала быть прерогативой исключительно крупных студий с большими бюджетами. WebGL открыл двери для создания трехмерных интерактивных сцен прямо в браузере — без плагинов и сложных настроек. Будь то визуализация архитектурного проекта, интерактивный каталог товаров или захватывающая игра — все это теперь доступно на обычном сайте. Но как начать работу с этой технологией, если вы только осваиваете трехмерное пространство в вебе? Давайте разберемся вместе. 🚀
Хотите быстро освоить создание впечатляющих 3D-сайтов? В курсе Обучение веб-разработке от Skypro вы не только изучите основы HTML, CSS и JavaScript, но и погрузитесь в мир трехмерной графики с WebGL. Наставники-практики покажут, как превратить обычный сайт в интерактивное 3D-пространство, которое запомнят ваши пользователи. От базовых принципов до продвинутых техник — ваш путь к созданию сайтов будущего начинается здесь!
Основы WebGL и подготовка среды разработки 3D-сайта
WebGL (Web Graphics Library) — это JavaScript API для рендеринга интерактивной трехмерной графики без использования плагинов. Он работает в любом современном браузере и использует графический процессор (GPU) для ускорения обработки и отображения графики. WebGL — это веб-стандарт, который дает разработчикам доступ к низкоуровневым графическим примитивам, похожим на OpenGL ES 2.0.
Прежде чем погрузиться в код, давайте подготовим рабочую среду:
- Редактор кода: Visual Studio Code, Sublime Text или любой другой по вашему предпочтению
- Веб-браузер: Chrome или Firefox с инструментами разработчика
- Локальный сервер: Live Server для VS Code или аналогичный плагин
Чистый WebGL требует написания шейдеров на языке GLSL и работы с матрицами трансформаций — это сложно для начинающих. Поэтому мы будем использовать библиотеку Three.js, которая значительно упрощает работу с 3D-графикой.
| Библиотека | Преимущества | Сложность | Лучше для |
|---|---|---|---|
| Чистый WebGL | Полный контроль, высокая производительность | Высокая | Продвинутых разработчиков |
| Three.js | Баланс между контролем и простотой, отличная документация | Средняя | Большинства проектов |
| Babylon.js | Встроенная физика, интеграция с GUI | Средняя | Игр и сложных интерактивных приложений |
| A-Frame | Декларативный HTML-синтаксис, VR-готовность | Низкая | Быстрых прототипов и VR |
Для установки Three.js вы можете использовать npm:
npm install three
Или подключить CDN в HTML-файле:
<script src="https://cdn.jsdelivr.net/npm/three@0.132.2/build/three.min.js"></script>
Артем Валевский, технический директор проекта
Помню, как в 2019 году к нам обратился клиент с амбициозным запросом — создать конфигуратор мебели с возможностью рассмотреть каждый предмет со всех сторон в режиме реального времени. У нас был опыт с 3D-моделированием, но не в веб-среде. Первые попытки использовать чистый WebGL оказались мучительными — мы тратили часы на отладку шейдеров и матричные преобразования.
Переломный момент наступил, когда мы перешли на Three.js. За два дня мы смогли создать работающий прототип с базовыми возможностями вращения и масштабирования моделей. Клиент был в восторге от скорости разработки! А мы поняли важный урок: не нужно изобретать велосипед, когда есть качественные библиотеки, которые решают базовые задачи.

Настройка проекта и интеграция WebGL в веб-страницу
Создадим базовую структуру проекта. Начнем с HTML-страницы, которая будет содержать наш 3D-контент:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My First WebGL Site</title>
<style>
body { margin: 0; overflow: hidden; }
canvas { display: block; }
</style>
</head>
<body>
<script src="https://cdn.jsdelivr.net/npm/three@0.132.2/build/three.min.js"></script>
<script src="main.js"></script>
</body>
</html>
Теперь создадим файл main.js, где напишем базовый код для инициализации WebGL-сцены с помощью Three.js:
// Основные компоненты сцены
let scene, camera, renderer;
// Функция инициализации
function init() {
// Создание сцены
scene = new THREE.Scene();
scene.background = new THREE.Color(0xf0f0f0);
// Создание камеры
camera = new THREE.PerspectiveCamera(
75, // угол обзора
window.innerWidth / window.innerHeight, // соотношение сторон
0.1, // ближняя плоскость отсечения
1000 // дальняя плоскость отсечения
);
camera.position.z = 5;
// Создание рендерера
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// Обработчик изменения размера окна
window.addEventListener('resize', onWindowResize);
// Запуск анимации
animate();
}
// Функция обновления камеры и рендерера при изменении размера окна
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
// Функция анимации
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
// Запуск приложения
init();
После запуска этого кода вы увидите пустую серую сцену. Теперь давайте разберемся с основными компонентами, которые мы использовали:
- Scene (Сцена): контейнер для всех объектов, камер и источников света.
- Camera (Камера): определяет, что именно мы видим. Мы используем PerspectiveCamera, которая имитирует зрение человека.
- Renderer (Рендерер): отвечает за отрисовку сцены с помощью WebGL.
Обратите внимание на функцию animate() — она создает цикл рендеринга с помощью requestAnimationFrame, который будет вызываться примерно 60 раз в секунду, обеспечивая плавную анимацию. 🔄
Создание базовых 3D-объектов и сцен на вашем сайте
Теперь, когда у нас есть базовая настройка, добавим на сцену некоторые 3D-объекты. Three.js предоставляет множество готовых геометрий для создания базовых фигур.
Давайте добавим в нашу функцию init() код для создания куба:
// В функции init() после создания рендерера
// Создание куба
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshBasicMaterial({ color: 0x44aa88 });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
// Добавляем анимацию вращения в функцию animate
function animate() {
requestAnimationFrame(animate);
// Вращение куба
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render(scene, camera);
}
Теперь у нас есть вращающийся куб! 🎲 Но давайте сделаем нашу сцену более интересной, добавив различные 3D-объекты с разными материалами:
// Создаем функцию для добавления объектов на сцену
function createObjects() {
// Куб
const cubeGeometry = new THREE.BoxGeometry(1, 1, 1);
const cubeMaterial = new THREE.MeshPhongMaterial({ color: 0x44aa88 });
const cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
cube.position.x = -2;
scene.add(cube);
// Сфера
const sphereGeometry = new THREE.SphereGeometry(0.8, 32, 32);
const sphereMaterial = new THREE.MeshPhongMaterial({ color: 0xaa8844 });
const sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
sphere.position.x = 0;
scene.add(sphere);
// Тор
const torusGeometry = new THREE.TorusGeometry(0.6, 0.2, 16, 100);
const torusMaterial = new THREE.MeshPhongMaterial({ color: 0x8844aa });
const torus = new THREE.Mesh(torusGeometry, torusMaterial);
torus.position.x = 2;
scene.add(torus);
// Добавляем свет
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(ambientLight);
const pointLight = new THREE.PointLight(0xffffff, 1);
pointLight.position.set(5, 5, 5);
scene.add(pointLight);
// Возвращаем объекты для анимации
return { cube, sphere, torus };
}
// В функции init() вызываем создание объектов
const objects = createObjects();
// Обновляем функцию animate для вращения всех объектов
function animate() {
requestAnimationFrame(animate);
// Вращение объектов
objects.cube.rotation.x += 0.01;
objects.cube.rotation.y += 0.01;
objects.sphere.rotation.x += 0.01;
objects.sphere.rotation.z += 0.01;
objects.torus.rotation.x += 0.01;
objects.torus.rotation.y += 0.01;
renderer.render(scene, camera);
}
Обратите внимание, что мы заменили MeshBasicMaterial на MeshPhongMaterial. Последний реагирует на свет, что делает наши объекты более реалистичными, но для его работы мы должны добавить источники света в сцену.
Вот список распространенных типов геометрий в Three.js:
| Геометрия | Описание | Типичное использование |
|---|---|---|
| BoxGeometry | Куб или прямоугольный параллелепипед | Строительные блоки, контейнеры |
| SphereGeometry | Сфера с настраиваемым разрешением | Планеты, мячи, частицы |
| CylinderGeometry | Цилиндр с настраиваемыми верхним/нижним радиусами | Колонны, стволы деревьев |
| ConeGeometry | Конус с настраиваемой высотой и радиусом | Маркеры, конусы |
| TorusGeometry | Кольцо (бублик) | Колесо, кольцо, декоративные элементы |
| PlaneGeometry | Плоская прямоугольная поверхность | Пол, стены, экраны |
Для сложных 3D-моделей лучше использовать импорт из внешних форматов, таких как glTF или OBJ. Three.js имеет загрузчики для различных форматов, которые позволяют импортировать модели, созданные в Blender, Maya или других 3D-редакторах.
Мария Соколова, 3D-дизайнер
Когда я начала сотрудничать с веб-разработчиками, существовал серьезный разрыв между созданием 3D-моделей в специализированных программах и их интеграцией в веб. Модели приходилось сильно упрощать, а текстуры сжимать до неузнаваемости.
Однажды мы работали над сайтом для музея современного искусства, где нужно было показать скульптуры в интерактивном формате. Я создала детализированные модели в Blender, но когда дело дошло до импорта в веб, возникли проблемы с производительностью.
Решением стало использование glTF формата и правильной оптимизации моделей. Мы разработали процесс, при котором сохраняли высокое качество визуализации, но при этом модели загружались быстро даже на мобильных устройствах. Секрет был в создании нескольких LOD-версий (Level of Detail) каждой модели и правильном запекании текстур и карт нормалей. После внедрения этой технологии виртуальная выставка работала безупречно, а посетители сайта проводили в среднем на 4 минуты больше времени, изучая экспонаты.
Работа с текстурами и освещением в 3D-графике на WebGL
Чтобы наши 3D-объекты выглядели реалистично, необходимо добавить текстуры и настроить освещение. Текстуры — это изображения, которые "оборачиваются" вокруг 3D-объекта, придавая ему детализированный вид.
Давайте модифицируем наш код, чтобы добавить текстуру к сфере:
// Загрузчик текстур
const textureLoader = new THREE.TextureLoader();
// Создаем функцию для добавления объектов на сцену
function createObjects() {
// ... Предыдущий код ...
// Сфера с текстурой
const sphereGeometry = new THREE.SphereGeometry(0.8, 32, 32);
// Загружаем текстуры
const earthTexture = textureLoader.load('textures/earth_map.jpg');
const earthBumpMap = textureLoader.load('textures/earth_bump.jpg');
const earthSpecMap = textureLoader.load('textures/earth_spec.jpg');
const sphereMaterial = new THREE.MeshPhongMaterial({
map: earthTexture,
bumpMap: earthBumpMap,
bumpScale: 0.05,
specularMap: earthSpecMap,
specular: new THREE.Color('grey'),
shininess: 15
});
const sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
sphere.position.x = 0;
scene.add(sphere);
// ... Остальной код ...
}
Здесь мы использовали несколько типов карт текстур:
- map: Основная цветовая текстура
- bumpMap: Карта неровностей, создающая иллюзию рельефа
- specularMap: Определяет, какие части поверхности более блестящие
Теперь давайте усовершенствуем освещение нашей сцены. Хорошее освещение критически важно для создания реалистичной 3D-среды:
// Функция для настройки освещения
function setupLighting() {
// Удаляем предыдущие источники света, если они есть
scene.children.forEach(child => {
if (child.isLight) scene.remove(child);
});
// Базовое окружающее освещение
const ambientLight = new THREE.AmbientLight(0xffffff, 0.3);
scene.add(ambientLight);
// Основной направленный свет (имитация солнца)
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
directionalLight.position.set(5, 3, 5);
directionalLight.castShadow = true; // Включаем отбрасывание теней
// Настройка области теней
directionalLight.shadow.camera.near = 0.5;
directionalLight.shadow.camera.far = 20;
directionalLight.shadow.camera.left = -5;
directionalLight.shadow.camera.right = 5;
directionalLight.shadow.camera.top = 5;
directionalLight.shadow.camera.bottom = -5;
// Разрешение карты теней
directionalLight.shadow.mapSize.width = 2048;
directionalLight.shadow.mapSize.height = 2048;
scene.add(directionalLight);
// Дополнительный мягкий свет с противоположной стороны
const fillLight = new THREE.DirectionalLight(0x9999ff, 0.3);
fillLight.position.set(-5, 3, -5);
scene.add(fillLight);
}
Для работы с тенями нужно также включить их в рендерере и настроить объекты для отбрасывания и приема теней:
// В функции init()
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap; // Мягкие тени
// Для объектов, которые должны отбрасывать тени
cube.castShadow = true;
sphere.castShadow = true;
torus.castShadow = true;
// Создаем пол для приема теней
const floorGeometry = new THREE.PlaneGeometry(20, 20);
const floorMaterial = new THREE.MeshPhongMaterial({
color: 0xeeeeee,
side: THREE.DoubleSide
});
const floor = new THREE.Mesh(floorGeometry, floorMaterial);
floor.rotation.x = Math.PI / 2;
floor.position.y = -2;
floor.receiveShadow = true;
scene.add(floor);
Различные типы материалов в Three.js по-разному взаимодействуют со светом:
- MeshBasicMaterial: Не реагирует на свет, всегда показывает свой базовый цвет
- MeshLambertMaterial: Матовая поверхность, реагирует на свет без бликов
- MeshPhongMaterial: Поверхность с бликами, имитирует пластик или металл
- MeshStandardMaterial: Физически корректное освещение с параметрами шероховатости и металличности
- MeshPhysicalMaterial: Расширенная версия StandardMaterial с дополнительными параметрами (прозрачность, преломление и т.д.)
Правильное сочетание текстур и освещения — это ключ к созданию реалистичных и привлекательных 3D-сцен. Экспериментируйте с различными типами материалов и источников света, чтобы добиться желаемого эффекта. ✨
Оптимизация и публикация 3D-сайта на базе WebGL
После создания впечатляющей 3D-сцены необходимо убедиться, что она будет работать быстро и плавно даже на устройствах с ограниченными ресурсами. Оптимизация — критически важный шаг в разработке WebGL-приложений.
Вот ключевые аспекты оптимизации производительности WebGL:
- Оптимизация моделей: Уменьшение количества полигонов, использование LOD (Level of Detail)
- Оптимизация текстур: Сжатие изображений, использование mipmaps, текстурных атласов
- Управление памятью: Освобождение неиспользуемых ресурсов, обработка событий потери контекста
- Эффективное рендеринг: Использование техник, таких как frustum culling, occlusion culling
Давайте реализуем некоторые из этих оптимизаций в нашем коде:
// Функция для управления ресурсами
function setupResourceManagement() {
// Миникарты для текстур – уменьшают артефакты при уменьшении объектов
textureLoader.setPath('textures/');
const textures = {
earth: textureLoader.load('earth_map.jpg', function(texture) {
texture.minFilter = THREE.LinearMipMapLinearFilter;
texture.generateMipmaps = true;
texture.anisotropy = renderer.capabilities.getMaxAnisotropy();
}),
};
// Функция для очистки ресурсов
function disposeResources() {
for (const key in textures) {
textures[key].dispose();
}
// Очистка геометрий и материалов
scene.traverse(object => {
if (object.isMesh) {
object.geometry.dispose();
if (object.material.isMaterial) {
disposeMaterial(object.material);
} else {
// Массив материалов
for (const material of object.material) {
disposeMaterial(material);
}
}
}
});
}
// Вспомогательная функция для очистки материалов
function disposeMaterial(material) {
for (const key in material) {
const value = material[key];
if (value && typeof value.dispose === 'function') {
value.dispose();
}
}
}
// Обработка потери контекста WebGL
const canvas = renderer.domElement;
canvas.addEventListener('webglcontextlost', function(event) {
event.preventDefault();
console.warn('WebGL context lost. Reinitializing...');
// Остановка анимации и очистка ресурсов
cancelAnimationFrame(animationId);
});
canvas.addEventListener('webglcontextrestored', function() {
console.info('WebGL context restored.');
// Переинициализация сцены
init();
});
// При закрытии страницы очищаем ресурсы
window.addEventListener('beforeunload', disposeResources);
return { textures, disposeResources };
}
Для лучшей производительности на различных устройствах можно реализовать адаптивное качество рендеринга:
// Функция для адаптации качества рендеринга
function setupAdaptiveQuality() {
let quality = 'high'; // По умолчанию высокое качество
const devicePixelRatio = window.devicePixelRatio || 1;
// Оценка возможностей устройства
const isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
const performanceNow = performance.now();
// Тест производительности
const testObject = new THREE.Mesh(
new THREE.BoxGeometry(1, 1, 1, 50, 50, 50),
new THREE.MeshBasicMaterial()
);
scene.add(testObject);
// Рендерим тестовый кадр
renderer.render(scene, camera);
scene.remove(testObject);
testObject.geometry.dispose();
testObject.material.dispose();
const renderTime = performance.now() – performanceNow;
// Определяем качество на основе теста и типа устройства
if (renderTime > 20 || isMobile) {
quality = 'low';
} else if (renderTime > 10) {
quality = 'medium';
}
// Настраиваем параметры рендерера в соответствии с качеством
switch(quality) {
case 'low':
renderer.setPixelRatio(Math.min(devicePixelRatio, 1));
renderer.setSize(window.innerWidth * 0.8, window.innerHeight * 0.8);
renderer.shadowMap.enabled = false;
break;
case 'medium':
renderer.setPixelRatio(Math.min(devicePixelRatio, 1.5));
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFShadowMap;
break;
case 'high':
renderer.setPixelRatio(devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
break;
}
return quality;
}
При публикации 3D-сайта важно учесть следующие аспекты:
| Аспект | Рекомендации |
|---|---|
| Загрузка ресурсов | Используйте прогрессивную загрузку, показывайте экран загрузки, предварительно загружайте критические ресурсы |
| Сжатие файлов | Минифицируйте JavaScript, используйте сжатие gzip/Brotli, оптимизируйте текстуры |
| CDN | Используйте CDN для распределения нагрузки и ускорения доставки ресурсов |
| Мобильная совместимость | Тестируйте на различных устройствах, предусматривайте альтернативы для устаревших браузеров |
| SEO | Используйте серверный рендеринг или предварительный рендеринг для индексации контента |
Для обеспечения загрузки и публикации сайта с оптимальной производительностью, необходимо правильно структурировать код и ресурсы:
// Создаем систему загрузки ресурсов
const loadingManager = new THREE.LoadingManager();
// Элементы UI для загрузки
const loadingElement = document.getElementById('loading-screen');
const progressBar = document.getElementById('progress-bar');
loadingManager.onProgress = function(url, itemsLoaded, itemsTotal) {
const progress = (itemsLoaded / itemsTotal * 100).toFixed(0);
progressBar.style.width = progress + '%';
progressBar.textContent = progress + '%';
};
loadingManager.onLoad = function() {
// Скрываем экран загрузки с анимацией fade-out
loadingElement.classList.add('fade-out');
// После завершения анимации полностью скрываем элемент
setTimeout(() => {
loadingElement.style.display = 'none';
}, 500);
// Запускаем основную анимацию
animate();
};
// Обновляем наш загрузчик текстур
const textureLoader = new THREE.TextureLoader(loadingManager);
🚀 После оптимизации и подготовки всех ресурсов, ваш WebGL-сайт готов к публикации! Разместите все файлы на веб-сервере, убедитесь, что сервер настроен для правильной отдачи MIME-типов для всех ресурсов, и наслаждайтесь вашим трехмерным веб-пространством.
Создание 3D-сайтов с WebGL открывает невероятные возможности для визуализации и интерактивности в вебе. Начав с простых фигур и постепенно добавляя сложность, вы можете создавать впечатляющие трехмерные интерфейсы, продуктовые визуализации или интерактивные истории. Ключ к успеху — баланс между визуальной привлекательностью и производительностью. Помните, что даже самый красивый 3D-сайт не будет эффективен, если пользователи покинут его из-за долгой загрузки или низкого FPS. Экспериментируйте, оптимизируйте, и превращайте ваши идеи в осязаемые трехмерные миры прямо в браузере!