Атлас спрайтов представляет собой единое изображение, в котором упаковано множество небольших графических элементов (иконок, маркеров, символов). Вместо загрузки десятков или сотен отдельных файлов используется одна текстура, внутри которой каждый элемент имеет координаты вырезки (UV-область).
Ключевая особенность подхода — сокращение количества запросов к сети и уменьшение переключений текстур в GPU, что критично для производительности в WebGL-пайплайне.
В экосистеме deck.gl атласы спрайтов применяются преимущественно в
слоях, работающих с символами и маркерами: IconLayer,
частично TextLayer, а также кастомных слоях через
TextureManager и шейдерные утилиты.
Атлас состоит из двух обязательных компонентов:
Типичная структура JSON:
{
"airport": {
"x": 0,
"y": 0,
"width": 64,
"height": 64,
"anchorX": 32,
"anchorY": 32
},
"harbor": {
"x": 64,
"y": 0,
"width": 64,
"height": 64,
"anchorX": 32,
"anchorY": 32
}
}
Каждый ключ соответствует имени спрайта, а значения задают:
Основной сценарий применения — отображение символов на карте.
import {IconLayer} from '@deck.gl/layers';
const layer = new IconLayer({
id: 'icons',
data,
iconAtlas: '/assets/icon-atlas.png',
iconMapping: '/assets/icon-atlas.json',
getIcon: d => d.type,
getPosition: d => d.coordinates,
getSize: 32,
sizeScale: 1
});
Здесь происходит ключевая связка:
iconAtlas — единое изображениеiconMapping — JSON с координатамиgetIcon — выбирает ключ из JSON для конкретного
объектаВ результате каждый объект данных получает свой спрайт без отдельной загрузки ресурсов.
WebGL не работает с «вырезанием изображений» на CPU. Вместо этого используется UV-разметка:
В deck.gl это реализуется через инстансинг: каждый
объект передает параметры в vertex shader, включая:
Атласы обычно создаются на этапе сборки проекта.
Распространённые инструменты:
TexturePackerSpritesmithsharp + кастомные скриптыПример генерации через Node.js:
const spritesmith = require('spritesmith');
const fs = require('fs');
spritesmith.run({
src: ['icons/*.png']
}, (err, result) => {
fs.writeFileSync('atlas.png', result.image);
fs.writeFileSync('atlas.json', JSON.stringify(result.coordinates));
});
На выходе формируется изображение и JSON-карта координат.
Для корректной работы в WebGL-среде необходимо учитывать:
Размытые границы возникают при дробных координатах UV. Поэтому:
Без отступов возникает bleeding эффект — смешивание пикселей соседних спрайтов.
Рекомендуется:
Для Retina-дисплеев часто используются:
В deck.gl масштабирование выполняется через
devicePixelRatio.
Типовая схема:
sizeScale корректирует визуальный размерnew IconLayer({
...
sizeScale: window.devicePixelRatio
});
Альтернативный подход — отдельные атласы @1x и
@2x с выбором по runtime-условию.
Помимо статических изображений, возможны динамические сценарии:
В этом случае используется Canvas API:
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
ctx.drawImage(img1, 0, 0);
ctx.drawImage(img2, 64, 0);
Далее canvas передается как текстура в слой.
Использование атласов напрямую влияет на:
IconLayer полностью опирается на атласы, тогда как
TextLayer использует собственный glyph atlas.
Glyph atlas устроен аналогично:
Это позволяет рендерить текст без постоянной rasterization операции.
UV-координаты в WebGL нормализуются в диапазон [0, 1].
Преобразование:
u = x / atlasWidth
v = y / atlasHeight
При этом важно учитывать:
Смещение иконок относительно геометрии приводит к визуальному дрейфу маркеров.
Проявляется как «грязные края» при масштабировании карты.
Даже небольшое смещение координат делает спрайты некорректными.
При превышении лимитов GPU атлас может не загрузиться или обрезаться.
Для крупных приложений применяются стратегии:
В некоторых случаях используется несколько уровней детализации, аналогично mipmapping:
Внутри архитектуры deck.gl атласы проходят следующий путь:
Этот механизм позволяет обрабатывать тысячи объектов без значительного падения FPS, сохраняя стабильную производительность даже при сложных визуализациях на карте.