Шейдеры и GLSL

Рендеринг в Mapbox GL JS основан на WebGL-пайплайне, в котором ключевую роль играют шейдеры, написанные на GLSL (OpenGL Shading Language). Вся визуализация карты — от геометрии линий до растеризации тайлов и анимации слоёв — в конечном счёте сводится к выполнению вершинных и фрагментных шейдеров на GPU.

Архитектура построена вокруг разделения на два уровня:

  • JavaScript-слой управления сценой (style, sources, layers)
  • GPU-слой исполнения (WebGL + GLSL)

JavaScript формирует данные и передаёт их в виде буферов, атрибутов и uniform-параметров, а шейдеры отвечают за финальную визуализацию каждого пикселя.


Роль GLSL в рендеринге карты

GLSL используется для описания двух основных стадий графического конвейера:

Вершинный шейдер (Vertex Shader)

Отвечает за преобразование геометрии:

  • перевод координат из мирового пространства в clip space
  • применение матриц проекции и вида
  • интерполяция атрибутов (цвет, толщина линии, смещения)
  • вычисление параметров для фрагментного шейдера

В контексте картографического рендеринга ключевая задача — преобразование координат долготы/широты в пиксельные координаты тайловой системы.


Фрагментный шейдер (Fragment Shader)

Отвечает за вычисление цвета каждого пикселя:

  • заливка полигонов
  • отрисовка линий с антиалиасингом
  • текстурирование тайлов
  • смешивание слоёв (blending)
  • применение динамических визуальных эффектов

Фрагментный шейдер фактически определяет визуальный стиль карты.


Координатные системы Mapbox GL JS

Рендеринг проходит через несколько преобразований координат:

1. Географические координаты

  • longitude / latitude (EPSG:4326)
  • исходная модель данных

2. Mercator projection

  • перевод в Web Mercator (EPSG:3857)
  • нелинейное искажение для отображения на плоскости

3. Tile coordinates

  • разбиение мира на тайлы
  • zoom-dependent масштабирование

4. Clip space

  • финальное преобразование через матрицы модели и камеры

Шейдеры работают преимущественно на последних двух этапах, получая уже подготовленные данные.


Пайплайн шейдеров в рендеринге карты

Рендеринг слоя в Mapbox GL JS проходит последовательные стадии:

  1. Загрузка геометрии из source (vector/raster tiles)
  2. Генерация vertex buffer objects (VBO)
  3. Передача атрибутов в GPU
  4. Выполнение vertex shader
  5. Rasterization (интерполяция примитивов)
  6. Выполнение fragment shader
  7. Blending с другими слоями

Каждый слой карты соответствует набору шейдерных программ.


Структура шейдеров в Mapbox GL JS

Шейдеры организованы как программные шаблоны с параметризацией через uniforms:

Uniform-параметры

Передают глобальные данные:

  • матрица проекции
  • zoom-уровень
  • время (для анимаций)
  • параметры стиля
  • цветовые переменные

Attributes

Данные на вершину:

  • координаты
  • цвет
  • индексы текстур
  • ширина линий

Varyings

Интерполируемые значения между vertex и fragment shader:

  • цветовые градиенты
  • расстояния вдоль линии
  • нормализованные координаты

GLSL векторная математика для картографии

Шейдеры активно используют встроенные типы GLSL:

  • vec2 — координаты
  • vec3 — RGB или 3D координаты
  • vec4 — RGBA или homogeneous coordinates
  • mat3 / mat4 — трансформации

Ключевые операции:

Нормализация координат

vec2 uv = normalize(position);

Линейная интерполяция

float t = mix(a, b, p);

Скалярное произведение

float d = dot(v1, v2);

Отрисовка линий и антиалиасинг

Линии в Mapbox GL JS не являются простыми геометрическими примитивами. Они строятся как экструзия (extrusion) вдоль векторного пути.

В шейдере вычисляется расстояние до центра линии:

  • центр линии = 0
  • граница = ±width/2

Антиалиасинг реализуется через плавный переход:

float alpha = smoothstep(edge0, edge1, distance);

Это позволяет избегать «рваных» краёв при масштабировании.


Работа с тайлами и LOD

Шейдеры учитывают уровень детализации (Level of Detail):

  • низкий zoom → агрегированные данные
  • высокий zoom → детализированные геометрии

LOD влияет на:

  • плотность вершин
  • толщину линий
  • видимость слоёв
  • генерацию паттернов

Фрагментные шейдеры используют zoom как параметр интерполяции:

float z = u_zoom;
float scale = pow(2.0, z);

Текстуры и растровые слои

Растровые данные (satellite, terrain) обрабатываются через texture sampling:

vec4 color = texture2D(u_image, uv);

Особенности:

  • тайлинг текстур
  • повторяемость координат
  • фильтрация (linear / nearest)
  • mipmapping для производительности

Шейдеры обеспечивают корректное смешивание растровых слоёв с векторными.


Динамические стили через шейдеры

Стилизация карты в Mapbox GL JS может быть частично перенесена в GLSL:

  • изменение цвета в зависимости от zoom
  • пульсация объектов
  • градиенты по высоте
  • визуализация плотности данных

Пример логики:

  • вход: density attribute
  • выход: цвет через gradient function

Пользовательские шейдеры и Custom Layer API

Mapbox GL JS предоставляет механизм внедрения собственных WebGL-слоёв через Custom Layer API.

Структура слоя:

  • onAdd — инициализация WebGL ресурсов
  • render — выполнение шейдеров
  • доступ к map matrices

Внутри custom layer можно:

  • создавать собственные GLSL программы
  • управлять буферами вручную
  • комбинировать с Mapbox стилями

Матрицы трансформации и камера

Ключевая часть vertex shader — работа с матрицами:

  • model matrix
  • view matrix
  • projection matrix

Финальное преобразование:

gl_Position = u_projectionMatrix * u_modelViewMatrix * vec4(position, 1.0);

Камера в Mapbox GL JS поддерживает:

  • pitch (наклон)
  • bearing (поворот)
  • zoom (масштаб)

Все эти параметры транслируются в GLSL как uniform-переменные.


Оптимизация шейдеров

Производительность критична для картографического рендеринга.

Основные техники:

Минимизация branching

Условия заменяются на математические функции:

float mask = step(0.5, value);

Использование precision qualifiers

precision mediump float;

Переиспользование varyings

Снижение вычислений во fragment shader

Атлас текстур

Объединение ресурсов в одну текстуру


Частые проблемы GLSL в картографическом рендеринге

Z-fighting

Возникает при наложении слоёв с близкими depth values

Precision artifacts

Различия между lowp/mediump/highp

Tile seams

Артефакты на границах тайлов

Floating point precision

Ошибки при больших координатах на высоких zoom уровнях


Архитектурная роль шейдеров в Mapbox GL JS

Шейдеры являются конечной точкой всей системы визуализации:

  • JavaScript определяет структуру сцены
  • стиль описывает визуальные правила
  • WebGL реализует исполнение
  • GLSL формирует пиксельный результат

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