Загрузка текстур

Текстура в WebGL представляет собой изображение, которое накладывается на геометрию для придания визуальной детализации. В контексте Deck.gl текстуры используются в слоях (layers) для отрисовки иконок, растровых данных, пользовательских маркеров, тайлов и сложных визуальных элементов.

Ключевая особенность работы с текстурами заключается в том, что GPU не может напрямую использовать произвольные изображения без предварительной загрузки, декодирования и передачи в виде WebGLTexture. Этот процесс требует строгого контроля над форматом, размером и состоянием данных.


Загрузка изображений и подготовка данных

Первый этап работы с текстурами — получение изображения из внешнего источника. В браузере это может быть:

  • HTTP/HTTPS URL
  • локальный файл (через bundler)
  • Blob URL
  • импортированный ресурс

Типовой механизм загрузки в экосистеме Deck.gl опирается на утилиты из loaders.gl, где изображение декодируется и приводится к формату, совместимому с WebGL.

import { loadImage } from '@loaders.gl/images';

async function loadTextureImage(url) {
  const image = await loadImage(url);
  return image; // HTMLImageElement или ImageBitmap
}

Важный аспект — асинхронность. Текстура не может быть создана до завершения загрузки и декодирования изображения.


Создание WebGL текстуры

После получения изображения оно преобразуется в GPU-ресурс. В Deck.gl это происходит внутри слоя, однако понимание низкоуровневого процесса критично для контроля производительности.

function createTexture(gl, image) {
  const texture = gl.createTexture();

  gl.bindTexture(gl.TEXTURE_2D, texture);

  gl.texImage2D(
    gl.TEXTURE_2D,
    0,
    gl.RGBA,
    gl.RGBA,
    gl.UNSIGNED_BYTE,
    image
  );

  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);

  gl.bindTexture(gl.TEXTURE_2D, null);

  return texture;
}

При создании текстуры важны параметры фильтрации и упаковки:

  • TEXTURE_MIN_FILTER — поведение при уменьшении
  • TEXTURE_MAG_FILTER — поведение при увеличении
  • LINEAR обеспечивает сглаживание

Ограничения размеров и степень двойки

Исторически WebGL накладывает ограничения на размеры текстур. Хотя современные реализации поддерживают NPOT (non-power-of-two), остаются ограничения:

  • mipmapping для NPOT может быть ограничен
  • некоторые режимы повторения (REPEAT) требуют power-of-two
  • производительность выше при выровненных размерах

Рекомендуемая практика — использование текстур с размерами 2ⁿ × 2ⁿ при сложных сценах.


Интеграция текстур в Deck.gl слои

Deck.gl инкапсулирует WebGL-логику, предоставляя высокоуровневые слои. Текстуры применяются через свойства слоёв, таких как:

  • IconLayer
  • BitmapLayer
  • TileLayer
  • кастомные Layer реализации

IconLayer и атлас текстур

Один из наиболее эффективных способов работы с текстурами — использование атласа иконок.

import { IconLayer } from '@deck.gl/layers';

const layer = new IconLayer({
  id: 'icon-layer',
  data: points,
  getPosition: d => d.coordinates,
  getIcon: d => d.iconName,
  getSize: 32,
  iconAtlas: 'icons.png',
  iconMapping: {
    marker: { x: 0, y: 0, width: 64, height: 64, mask: true }
  }
});

Атлас представляет собой единое изображение, содержащие множество иконок. Это снижает количество текстурных биндов и улучшает производительность GPU.


BitmapLayer и растровые текстуры

BitmapLayer используется для отображения больших изображений, карт или подложек.

import { BitmapLayer } from '@deck.gl/layers';

const layer = new BitmapLayer({
  id: 'bitmap-layer',
  image: 'https://example.com/tiles/map.png',
  bounds: [-74.1, 40.7, -73.9, 40.8]
});

В этом случае текстура привязывается к географическим координатам через bounding box. Deck.gl автоматически выполняет трансформацию в экранное пространство.


Кэширование и повторное использование текстур

Загрузка изображений — дорогостоящая операция. Deck.gl и loaders.gl используют кэширование на нескольких уровнях:

  • HTTP-кэш браузера
  • внутренний cache загруженных ресурсов
  • GPU-кэш текстур

Повторное использование одинаковых URL позволяет избежать повторной загрузки и повторного создания WebGL-ресурсов.


Mipmapping и качество масштабирования

Mipmapping представляет собой набор уменьшенных копий текстуры, используемых при отрисовке объектов вдали.

gl.generateMipmap(gl.TEXTURE_2D);

Преимущества:

  • снижение aliasing
  • повышение стабильности при зуме
  • уменьшение артефактов мерцания

В Deck.gl mipmapping используется автоматически при соответствующих настройках слоёв и поддержке формата изображения.


Форматы изображений и декодирование

Поддерживаемые форматы:

  • PNG — прозрачность, высокая совместимость
  • JPEG — сжатие без альфа-канала
  • WebP — баланс качества и размера
  • AVIF — высокая степень сжатия (в современных браузерах)

Декодирование может происходить:

  • в основном потоке (Image)
  • в ImageBitmap (оптимизировано)
  • через Web Workers (в зависимости от загрузчика)

Использование ImageBitmap снижает нагрузку на главный поток и ускоряет upload в GPU.


Icon atlas и mapping как стратегия оптимизации

При большом количестве маркеров создание отдельной текстуры для каждой иконки приводит к деградации производительности. Решение — объединение в атлас.

Структура mapping:

{
  car: { x: 0, y: 0, width: 64, height: 64, anchorY: 64 },
  bus: { x: 64, y: 0, width: 64, height: 64, anchorY: 64 }
}

Каждая иконка описывается:

  • координатами в атласе
  • размером
  • точкой привязки (anchor)
  • режимом маскирования

GPU использует UV-координаты для выборки нужного фрагмента.


UV-координаты и привязка текстур

Текстуры отображаются через нормализованные координаты:

  • 0.0 — начало
  • 1.0 — конец

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

Пример концепции:

  • прямоугольник → 4 вершины
  • каждая вершина → (x, y, u, v)

Deck.gl генерирует эти данные автоматически для стандартных слоёв.


Поведение при повторении текстур

WebGL поддерживает режимы:

  • CLAMP_TO_EDGE
  • REPEAT
  • MIRRORED_REPEAT

В Deck.gl выбор режима зависит от типа слоя и характера изображения. Например:

  • карты и тайлы — CLAMP_TO_EDGE
  • паттерны — REPEAT

Асинхронная загрузка и жизненный цикл слоя

Текстуры в Deck.gl загружаются в рамках жизненного цикла слоя:

  1. инициализация слоя
  2. загрузка изображения
  3. создание WebGL texture
  4. обновление uniforms
  5. рендер

При обновлении данных возможно:

  • переиспользование текстуры
  • замена изображения
  • частичное обновление атласа

Ошибки и типовые проблемы загрузки текстур

На практике встречаются следующие проблемы:

CORS блокировка

  • изображение загружено с другого домена без заголовков

premultiplied alpha несоответствие

  • неправильная обработка прозрачности

несовпадение размеров атласа

  • неправильные UV координаты

утечка GPU памяти

  • отсутствие удаления текстур при уничтожении слоя

Оптимизация работы с текстурами

Основные стратегии:

  • использование атласов вместо отдельных изображений
  • применение ImageBitmap
  • минимизация размеров текстур
  • предварительная загрузка ресурсов
  • переиспользование texture objects
  • отключение mipmaps при отсутствии необходимости

Эффективная работа с текстурами напрямую влияет на FPS при больших наборах геоданных и визуализаций.