Texture atlasing

Texture atlasing — техника объединения нескольких текстур в один большой спрайтовый атлас. Основная цель — снижение количества вызовов рендеринга (draw calls) и оптимизация производительности WebGL-приложений. В Three.js она особенно актуальна при работе с большим количеством объектов, использующих одни и те же материалы с разными текстурами.


Основные принципы атласирования текстур

Атласирование строится на нескольких ключевых моментах:

  1. Объединение текстур Несколько маленьких изображений (например, 256×256 px) объединяются в один большой атлас (например, 2048×2048 px). Это позволяет GPU выполнять меньше переключений текстур во время рендеринга сцены.

  2. UV-координаты При использовании атласа необходимо корректировать UV-координаты каждого объекта. В UV-пространстве [0, 1] каждая часть атласа соответствует отдельной текстуре. Если объект использует только часть атласа, UV нужно масштабировать и сдвигать так, чтобы они указывали на нужный регион.

  3. Форматы и фильтрация Атлас должен быть в формате, поддерживаемом GPU (например, PNG или JPEG). Следует учитывать фильтрацию: линейная фильтрация может привести к смешиванию цветов по краям отдельных текстур. Для предотвращения артефактов применяют padding — небольшие пустые границы между изображениями внутри атласа.


Создание текстурного атласа в Three.js

Three.js не предоставляет встроенных инструментов для генерации атласов на лету, поэтому обычно используют сторонние библиотеки или генерацию атласа на этапе сборки проекта.

Пример ручного создания атласа:

import * as THREE from 'three';

// Загружаем отдельные текстуры
const loader = new THREE.TextureLoader();
const tex1 = loader.load('image1.png');
const tex2 = loader.load('image2.png');

// Создаём канвас для атласа
const canvas = document.createElement('canvas');
canvas.width = 512;
canvas.height = 256;
const ctx = canvas.getContext('2d');

// Рисуем текстуры в канвас
ctx.drawImage(tex1.image, 0, 0);
ctx.drawImage(tex2.image, 256, 0);

// Создаём текстуру Three.js из канваса
const atlasTexture = new THREE.CanvasTexture(canvas);

// Применяем к материалу
const material = new THREE.MeshBasicMaterial({ map: atlasTexture });

После этого необходимо корректировать UV-координаты. Например, если первая текстура занимает левую половину атласа:

geometry.faceVertexUvs[0].forEach(uvs => {
    uvs.forEach(uv => {
        uv.x *= 0.5; // сжатие по горизонтали
    });
});
geometry.uvsNeedUpdate = true;

Для второй текстуры сдвиг по X будет равен 0.5, а масштаб 0.5.


Автоматизация с помощью библиотек

Для крупных проектов удобно использовать генераторы атласов, такие как:

  • TexturePacker — коммерческий инструмент с экспортом в формат JSON, удобный для анимаций спрайтов.
  • SpriteSheet.js или webpack-image-atlas-plugin — позволяют объединять изображения в атлас на этапе сборки.

Three.js позволяет легко интегрировать JSON-данные, содержащие координаты спрайтов, с помощью THREE.Texture и THREE.Mesh.


Применение атласов в анимации спрайтов

Texture atlasing особенно эффективен для спрайт-анимаций. Один атлас может содержать все кадры анимации персонажа, что позволяет анимировать объект, меняя UV-координаты вместо загрузки новых текстур.

Пример циклической анимации:

const frames = [
  { x: 0, y: 0, w: 0.25, h: 1 }, // кадр 1
  { x: 0.25, y: 0, w: 0.25, h: 1 }, // кадр 2
  // ...
];

let currentFrame = 0;

function animate() {
  requestAnimationFrame(animate);
  
  const frame = frames[currentFrame];
  geometry.faceVertexUvs[0].forEach(uvs => {
    uvs.forEach(uv => {
      uv.x = uv.x * frame.w + frame.x;
      uv.y = uv.y * frame.h + frame.y;
    });
  });
  geometry.uvsNeedUpdate = true;
  
  currentFrame = (currentFrame + 1) % frames.length;
  renderer.render(scene, camera);
}

animate();

Советы по оптимизации

  • Использовать один атлас на материал, чтобы сократить draw calls.
  • Учитывать padding для предотвращения смешивания цветов при mipmapping.
  • Стараться использовать текстуры кратные степеням 2, чтобы избежать проблем с фильтрацией на некоторых GPU.
  • Для динамических объектов можно создавать атлас на лету через CanvasTexture, но лучше подготовить заранее для статических моделей.

Texture atlasing позволяет значительно улучшить производительность Three.js-приложений при работе с множеством объектов и анимаций. Корректная работа с UV и продуманная структура атласов делают сцену более лёгкой для GPU и обеспечивают плавный рендеринг даже на слабых устройствах.