UV-развёртка и маппинг координат

В 3D-графике UV-развёртка представляет собой процесс проекции поверхности 3D-модели на двумерную плоскость для корректного отображения текстур. Каждая вершина модели получает свои UV-координаты (u, v), где u и v находятся в диапазоне от 0 до 1, соответствуя горизонтальной и вертикальной координатам текстуры.

В Three.js текстурные координаты используются в материалах через свойство geometry.attributes.uv. Для большинства стандартных геометрий (BoxGeometry, SphereGeometry, PlaneGeometry) UV-координаты генерируются автоматически. Для кастомных геометрий необходимо задавать их вручную.

const geometry = new THREE.BoxGeometry(1, 1, 1);
console.log(geometry.attributes.uv.array); // вывод массива UV-координат

Принципы маппинга текстур

Маппинг — процесс сопоставления пикселей текстуры с полигонами модели. Three.js поддерживает несколько типов маппинга:

  1. UVMapping (по умолчанию) — использование координат uv для текстуры.
  2. CubeReflectionMapping / CubeRefractionMapping — отражение и преломление на основе кубической карты.
  3. SphericalReflectionMapping — сферическая проекция для отражающих поверхностей.
  4. EquirectangularReflectionMapping — используется для HDR-текстур окружения.

Для материалов MeshBasicMaterial, MeshStandardMaterial и подобных текстура задаётся через свойство map:

const texture = new THREE.TextureLoader().load('texture.jpg');
const material = new THREE.MeshStandardMaterial({ map: texture });
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);

UV-координаты определяют, какая область текстуры попадёт на конкретный полигон. Например, u=0, v=0 соответствует левому нижнему углу текстуры, а u=1, v=1 — правому верхнему.

Генерация и корректировка UV-координат

Для сложных моделей часто необходимо редактировать UV-развёртку вручную. В Three.js можно использовать следующие подходы:

  • Пересчёт UV с помощью BufferGeometry: Каждая вершина содержит атрибут uv, который можно изменить программно:
const uvAttribute = geometry.attributes.uv;
for (let i = 0; i < uvAttribute.count; i++) {
    const u = uvAttribute.getX(i);
    const v = uvAttribute.getY(i);
    uvAttribute.setXY(i, u * 0.5, v * 0.5); // масштабирование UV
}
uvAttribute.needsUpdate = true;
  • Проецирование текстуры на основе координат XYZ: Для процедурных текстур или автоматической развёртки часто используется метод BoxProjection или сферическая проекция:
geometry.computeBoundingBox();
const max = geometry.boundingBox.max;
const min = geometry.boundingBox.min;

const uvAttribute = new THREE.BufferAttribute(new Float32Array(geometry.attributes.position.count * 2), 2);
for (let i = 0; i < geometry.attributes.position.count; i++) {
    const x = geometry.attributes.position.getX(i);
    const y = geometry.attributes.position.getY(i);
    const z = geometry.attributes.position.getZ(i);
    
    const u = (x - min.x) / (max.x - min.x);
    const v = (y - min.y) / (max.y - min.y);
    
    uvAttribute.setXY(i, u, v);
}
geometry.setAttribute('uv', uvAttribute);

Этот способ полезен для плоских или кубических объектов.

Проблемы и искажения UV-развёртки

Основные источники ошибок при маппинге:

  • Растяжение текстуры — если полигоны сильно отличаются по размеру на UV-карте.
  • Перекрытие UV — когда несколько полигонов используют одинаковую область текстуры.
  • Неправильная ориентация — поворот или зеркалирование UV-координат.

Для исправления используют разделение UV-сегментов (islands) и корректировку масштаба каждой части вручную в редакторах типа Blender с последующим экспортом.

Использование нескольких текстур

Three.js поддерживает несколько карт в одном материале:

  • map — основная текстура.
  • aoMap — карта окружающего освещения.
  • normalMap — карта нормалей для имитации микродеталей.
  • roughnessMap, metalnessMap, displacementMap — специальные карты для PBR-материалов.

Для каждой карты важны корректные UV. aoMap и displacementMap по умолчанию используют те же UV, что и map, но можно использовать отдельный атрибут uv2:

geometry.setAttribute('uv2', geometry.attributes.uv.clone());
material.aoMap = textureAO;
material.aoMapIntensity = 1.0;

Инструменты визуализации UV в Three.js

Для отладки можно использовать LineSegments для визуального отображения сетки UV на модели. Это позволяет увидеть, какие участки текстуры применяются к полигонам и выявить растяжения.

const wireframe = new THREE.WireframeGeometry(geometry);
const line = new THREE.LineSegments(wireframe);
line.material.depthTest = false;
line.material.opacity = 0.5;
line.material.transparent = true;
scene.add(line);

Практические рекомендации

  • Для стандартных геометрий использовать встроенные UV — достаточно для большинства текстур.
  • Для сложных или кастомных моделей создавать UV-развёртку в 3D-редакторе с последующим экспортом.
  • Проверять UV на растяжение, перекрытия и ориентацию до наложения текстур.
  • Использовать отдельные UV-атрибуты для карт типа aoMap или displacementMap.
  • Масштабировать и смещать UV при необходимости программно для процедурных текстур.

Эффективная работа с UV и текстурами обеспечивает реалистичное отображение материала, позволяет корректно использовать PBR-материалы и минимизирует визуальные артефакты на моделях.