Создание 3D сцен с помощью библиотеки Three.js

Раздел: Веб-разработка -> 3D графика в браузере

Библиотека three.js предоставляет инструменты для создания трехмерной графики в браузере. С её помощью можно строить сцены, анимировать объекты, загружать модели и многое другое. Далее рассмотрены основные приёмы работы.

Базовое создание сцены с объектом

Каким образом можно отобразить вращающийся 3D объект на веб-странице?

Цель:

Показать минимальный код для отображения вращающегося куба с эффектом перспективы.

// Подключаем three.js через CDN или модуль
import * as THREE from 'three';

// Сцена, камера, рендерер
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 5;

const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

// Геометрия и материал
const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);

// Освещение
const light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(1, 1, 1);
scene.add(light);

// Анимация
function animate() {
  requestAnimationFrame(animate);
  cube.rotation.x += 0.01;
  cube.rotation.y += 0.01;
  renderer.render(scene, camera);
}
animate();

Three js (three.js)

В браузере появится зелёный куб, медленно вращающийся вокруг осей X и Y.

Возможные проблемы:

  • Куб не отображается – проверьте, что камера направлена на объект и не находится внутри него.
  • Ошибки CORS при загрузке из CDN – используйте локальный сервер или явно укажите версию.
  • Тёмный экран – добавлено ли освещение? MeshStandardMaterial требует источников света.

Случаи использования:

Этот шаблон подходит для любых прототипов 3D сцен: от простых демонстраций до интерактивных витрин.

Варианты настройки сцены

Какой тип камеры выбрать для сцены?

Цель:

Сравнить перспективную и ортографическую камеры для разных задач.

// Перспективная камера (PerspectiveCamera)
const perspCamera = new THREE.PerspectiveCamera(
  75,                      // поле обзора в градусах
  window.innerWidth / window.innerHeight, // соотношение сторон
  0.1,                     // ближняя плоскость отсечения
  1000                     // дальняя плоскость отсечения
);

// Ортографическая камера (OrthographicCamera)
const aspect = window.innerWidth / window.innerHeight;
const orthoCamera = new THREE.OrthographicCamera(
  -1 * aspect, 1 * aspect,  // левая, правая границы
  1, -1,                    // верхняя, нижняя границы
  0.1, 1000                 // ближняя, дальняя плоскости
);
Перспективная камера создаёт иллюзию глубины, ортографическая сохраняет реальные размеры объекта независимо от расстояния.

Типичные ошибки:

  • Неправильные значения near/far – если задать слишком маленький near (<0.01), могут возникнуть артефакты z-борьбы. Слишком большой near отсечёт объект.
  • Для ортографической камеры часто забывают пересчитать границы при изменении размеров окна.

Случаи использования:

Перспективная – для виртуальных туров, игр, архитектурной визуализации. Ортографическая – для изометрических игр, 2D интерфейсов с 3D элементами.

Как добавить освещение и тени в three.js?

Цель:

Настроить источники света и отбрасывание теней для реалистичности.

// Включаем рендеринг теней
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;

// Направленный свет с тенями
const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
directionalLight.position.set(2, 3, 4);
directionalLight.castShadow = true;
directionalLight.shadow.mapSize.width = 1024;
directionalLight.shadow.mapSize.height = 1024;
scene.add(directionalLight);

// Вспомогательная плоскость для приёма теней
const planeGeometry = new THREE.PlaneGeometry(5, 5);
const planeMaterial = new THREE.MeshStandardMaterial({ color: 0xeeeeee });
const plane = new THREE.Mesh(planeGeometry, planeMaterial);
plane.rotation.x = -Math.PI / 2;
plane.position.y = -1;
plane.receiveShadow = true;
scene.add(plane);

// Куб отбрасывает тень
cube.castShadow = true;
Куб отбрасывает тень на плоскость, создавая ощущение пространства.

Проблемы:

  • Тени не видны – проверьте, что у объектов установлены castShadow/receiveShadow, что источник света castShadow = true, и что включён shadowMap у рендерера.
  • Тени низкого качества – увеличьте shadow.mapSize.width/height.
  • Свет не попадает на объект – проверьте дальность тени (shadow.camera.near/far).

Случаи использования:

Любая сцена, где важна визуальная глубина: игры, 3D редакторы, симуляторы.

Как загрузить и отобразить готовую 3D модель?

Цель:

Показать загрузку модели в формате glTF с помощью GLTFLoader.

import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';

const loader = new GLTFLoader();
loader.load(
  'path/to/model.glb',
  function (gltf) {
    scene.add(gltf.scene);
    // Настроить масштаб, позицию при необходимости
    gltf.scene.position.set(0, 0, 0);
  },
  function (xhr) {
    console.log((xhr.loaded / xhr.total * 100) + '% загружено');
  },
  function (error) {
    console.error('Ошибка загрузки модели', error);
  }
);
После загрузки модель появляется в сцене. Прогресс отображается в консоли.

Типичные ошибки:

  • CORS – если файл лежит на другом домене, сервер должен отдавать заголовки CORS. Решение – разместить модель локально или настроить сервер.
  • Модель не видна – проверьте, что она не слишком мала или не находится внутри стены. Часто помогает сбросить позицию и масштаб.
  • Отсутствие текстур – многие glTF содержат внешние текстуры, их пути должны быть корректны относительно файла модели.

Случаи использования:

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

Расширенные примеры использования three.js

Управление камерой с помощью OrbitControls

Описание:

Добавление интерактивного управления вращением и масштабированием сцены.

Пример
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true; // плавное движение
controls.dampingFactor = 0.05;
controls.screenSpacePanning = true;

function animate() {
  requestAnimationFrame(animate);
  controls.update(); // необходимо для damping
  renderer.render(scene, camera);
}
animate();
Теперь пользователь может вращать сцену мышью, приближать и отдалять колесом. Damping добавляет инерцию.

Система частиц (Points)

Описание:

Создание анимированного облака из 5000 частиц.

Пример
const particleCount = 5000;
const positions = new Float32Array(particleCount * 3);
for (let i = 0; i < particleCount * 3; i += 3) {
  positions[i] = (Math.random() - 0.5) * 20;
  positions[i+1] = (Math.random() - 0.5) * 20;
  positions[i+2] = (Math.random() - 0.5) * 20;
}

const geometry = new THREE.BufferGeometry();
geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));

const material = new THREE.PointsMaterial({
  color: 0x88aaff,
  size: 0.1,
  transparent: true,
  opacity: 0.8
});

const particles = new THREE.Points(geometry, material);
scene.add(particles);

// Анимация вращения
function animateParticles() {
  requestAnimationFrame(animateParticles);
  particles.rotation.y += 0.001;
  renderer.render(scene, camera);
}
animateParticles();
На экране медленно вращается звёздное поле из голубых точек.

Вариации:

Можно задать текстуру частицы через material.map, использовать PointsMaterial для имитации дыма, огня.

Простой шейдер с uniform time

Описание:

Написание собственного Material с ShaderMaterial и анимацией цвета во времени.

Пример
const vertexShader = `
  varying vec3 vPosition;
  void main() {
    vPosition = position;
    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
  }
`;

const fragmentShader = `
  uniform float uTime;
  varying vec3 vPosition;
  void main() {
    vec3 color = 0.5 + 0.5 * cos(uTime + vPosition.xyz * 2.0);
    gl_FragColor = vec4(color, 1.0);
  }
`;

const material = new THREE.ShaderMaterial({
  uniforms: {
    uTime: { value: 0 }
  },
  vertexShader: vertexShader,
  fragmentShader: fragmentShader
});

const sphere = new THREE.Mesh(new THREE.SphereGeometry(1, 32, 32), material);
scene.add(sphere);

// Обновление времени в анимации
function animateShader() {
  requestAnimationFrame(animateShader);
  material.uniforms.uTime.value += 0.01;
  renderer.render(scene, camera);
}
animateShader();
Сфера переливается радужными цветами, изменяющимися со временем.

Примечание:

Шейдеры позволяют создавать уникальные эффекты, не достижимые стандартными материалами.

three.js - comments

En
Three js (javascript)