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

Для того чтобы лучше понимать контекст последующего материала ожидается что у тебя уже есть знания js, а также react. Также заранее оговорюсь что буду использовать упрощенное объяснения для наилучшего восприятия.

Содержание

  • Основные сущности threejs

  • Основные части модели

  • Загрузка модели

  • Загрузка анимации

  • Threejs и React

Основные сущности Three.js

Three.js построен вокруг нескольких ключевых сущностей. Разберём их с примерами кода.

Сцена — это контейнер (объект), в который ты помещаешь все объекты: геометрию, свет, модели, эффекты и т.п.

const scene = new THREE.Scene();
scene.background = new THREE.Color(0x222222); // тёмно-серый фон

Камера — это глаз пользователя, который видит сцену. Объекты не отображаются, если они вне поля зрения камеры.

const camera = new THREE.PerspectiveCamera(
  75,                             // угол обзора (FOV)
  window.innerWidth / window.innerHeight, // соотношение сторон
  0.1,                            // ближняя плоскость отсечения
  1000                            // дальняя плоскость отсечения
);
camera.position.set(0, 1, 5); // камера смотрит с точки (0, 1, 5)

Рендерер — это компонент, который переводит сцену и камеру в пиксели, т.е. отрисовывает результат на HTML-экране. Более подробно разберем во 2 части статьи.

const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight); // размеры вьюпорта
document.body.appendChild(renderer.domElement); // <canvas> элемент, вставляемый в DOM

Как они работают вместе ?

Ты → создаёшь объекты → добавляешь их в сцену
Камера → “смотрит” на сцену
Рендерер → рисует это в на экране

Так а что же на счет 3d моделей ради которых мы и собрались? Давай разберем их чуть подробнее.

Основные части модели

Что же такое модель ?

3D-модель — это структура, описывающая форму, материалы, текстуры и поведение объекта.

Как ты уже понял по описанию сущность состоит из нескольких компонентов. Давай разберемся в них подробнее.

Геометрия (Geometry) - это форма модели: вершины, грани, координаты и нормали.

  • Вершины (vertices) — точки в 3D-пространстве

  • Грани (faces) — треугольники между вершинами

  • Нормали — направление, в которое “смотрит” поверхность

  • UV — координаты наложения текстур

Более подробно разберем во 2 части статьи

Материалы (Materials) - описывают, как должна выглядеть поверхность: цвет, отражения, прозрачность.

В Threejs есть множество материалов, которые служат абстракцией для наилучшего описания нужного материла. Основной MeshStandardMaterial:

const standardMaterial = new THREE.MeshStandardMaterial({
  color: 0xffffff,
  metalness: 0.8,
  roughness: 0.2
});

MeshStandardMaterial, поддерживает следующие параметры:

  • color

  • roughness

  • metalness

  • emissive

  • alpha (прозрачность)

Для более продвинутых кейсов также существует MeshPhysicalMaterial, данный материал отличается более реалистичным отображением и фактически существует только в рамках threejs, к нему может быть автоматически преобразован материал модели с настройками отражения.

Текстуры (Textures) - это изображения, которые накладываются на материал для создания реалистичности.

Типы текстур:

  • diffuse / baseColor — основной цвет

  • normalMap — фейковая детализация рельефа

  • metalnessMap, roughnessMap - блеск

  • aoMap — ambient occlusion (тени)

  • emissiveMap — подсветка

const textureLoader = new THREE.TextureLoader();
const texture = textureLoader.load('/textures/wood.jpg');
const material = new THREE.MeshStandardMaterial({ map: texture });

Загрузка модели

Загрузка моделей может отличаться в зависимости от формата самой модели. Однако для наиболее популярных форматов подойдет GLTFLoader. В случае более экзотических форматов можно использовать Loader с кастомным поведением


import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';

const loader = new GLTFLoader();
loader.load('/models/robot.glb', (gltf) => {
  scene.add(gltf.scene);
});

Загрузка анимации

Каждая модель может содержать анимацию, если она была заложена на этапе создания этой модели 3d-дизайнером.

В рамках threejs это можно проверить если модель содержит анимации (gltf.animations.length > 0), используй THREE.AnimationMixer:

let mixer;
const clock = new THREE.Clock();

loader.load('/models/fox.glb', (gltf) => {
  const model = gltf.scene;
  scene.add(model);

  mixer = new THREE.AnimationMixer(model);

  // Проигрываем первую анимацию
  const action = mixer.clipAction(gltf.animations[0]);
  action.play();
});

function animate() {
  requestAnimationFrame(animate);
  const delta = clock.getDelta();
  mixer?.update(delta);
  renderer.render(scene, camera);
}

Threejs и React

Для работы с Three.js в React чаще всего используется следующие пакеты:

@react-three/fiber - обертка над Three.js через JSX (аналог react-dom, но для WebGL)

@react-three/drei - Набор готовых компонентов: OrbitControls, Stage, Text, Gizmo, Loader и т.д.

@react-three/postprocessing - Эффекты постобработки (bloom, depth of field, glitch и пр.)

import { Canvas } from '@react-three/fiber';
import { OrbitControls, Stage } from '@react-three/drei';

export default function App() {
  return (
    <Canvas>
      <Stage environment="city" intensity={0.6}>
        <mesh>
          <boxGeometry args={[1, 1, 1]} />
          <meshStandardMaterial color="skyblue" />
        </mesh>
      </Stage>
      <OrbitControls />
    </Canvas>
  );
}

Как видно из примера буквально в одну строчку кода можно описать нужное поведение. Например OrbitControls позволяет вращать камеру относительно сцены. А Stage добавляет пресет заднего фона с освещением. Работа с моделями также упрощена все настройки оборачиваются в mesh и внутри него описываются геометрия и материал, то есть составные части модели.

Также добавлен хук для упрощенной загрузки моделей - useGLTF

// ModelViewer.jsx
import { useGLTF } from '@react-three/drei';

export default function ModelViewer(props) {
  const { scene } = useGLTF('/models/robot.glb');
  return <primitive object={scene} scale={1.5} {...props} />;
}

Далее можно вставить данную компоненту прямо в сцену как и любую другую компоненту в обычном react приложении.

Кроме того добавлен хук для загрузки текстур - useTextures

// CrateModel.jsx
import { useGLTF, useTexture } from '@react-three/drei';
import * as THREE from 'three';

export default function CrateModel(props) {
  // Загружаем модель
  const { nodes } = useGLTF('/models/crate.glb');

  // Загружаем текстуры
  const textureProps = useTexture({
    map: '/textures/crate_diffuse.jpg',
    roughnessMap: '/textures/crate_roughness.jpg',
    normalMap: '/textures/crate_normal.jpg',
  });

  // Настройка обёртки текстур (по желанию)
  Object.values(textureProps).forEach((tex) => {
    tex.wrapS = tex.wrapT = THREE.RepeatWrapping;
    tex.repeat.set(1, 1);
  });

  return (
    <mesh
      geometry={nodes.Crate.geometry}
      {...props}
      castShadow
      receiveShadow
    >
      <meshStandardMaterial
        {...textureProps}
        metalness={0.1}
        roughness={1}
      />
    </mesh>
  );
}

Мы разобрали базу, без которой дальше никуда. Я надеюсь как минимум избавил тебя от переживаний, что работа с моделями это что-то из жанра фантастики и все намного проще чем кажется, если разобраться в ключевых аспектах.

В следующей части копнём глубже: как работает сам WebGL под капотом, что на самом деле делает Three.js и как всё это грамотно оптимизировать, чтобы сцена не лагала даже на мобилках. Будет интересно.

Комментарии (5)


  1. cmyser
    16.07.2025 07:01

    Супер, жду продолжения


  1. jeny_tat
    16.07.2025 07:01

    Искала золото, нашла бриллиант. Как раз начала интересоваться данной библиотекой. Не знаю будет продолжение или нет, но тема очень интересная


    1. AlanNabiev Автор
      16.07.2025 07:01

      Спасибо, уже работаю над продолжением с подробным объяснением работы threejs с WebGL


  1. amXCVI
    16.07.2025 07:01

    Очень жду продолжение

    Особенно круто было бы почитать про реализацию web AR


    1. AlanNabiev Автор
      16.07.2025 07:01

      Спасибо, очень интересная тема обязательно рассмотрю ее в будущих статьях