Текстурирование полигонов

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

Текстурирование в контексте WebGL и Deck.gl основано на наложении растрового изображения на геометрическую поверхность с использованием UV-координат. Для полигонов это означает, что каждая вершина получает набор координат (u, v), определяющих, как пиксели текстуры проецируются на поверхность.

В Deck.gl текстурирование чаще всего реализуется через слой PolygonLayer, который поддерживает как простую заливку цветом, так и использование изображений в качестве материала поверхности. Текстура интерпретируется как двумерный массив данных, который «оборачивается» по площади полигона согласно правилам UV-развёртки.

Ключевые свойства:

  • изображение загружается как WebGL-текстура;
  • каждая вершина полигона получает UV-координаты;
  • фрагментный шейдер вычисляет цвет пикселя на основе текстуры;
  • применяется смешивание с цветом (tinting) и альфа-каналом.

Архитектура PolygonLayer и механизм заливки текстурой

PolygonLayer в Deck.gl опирается на три ключевых этапа обработки данных:

  1. Тесселяция полигонов Любой полигон (включая GeoJSON) преобразуется в набор треугольников. Это необходимо, поскольку GPU работает с треугольной геометрией.

  2. Генерация атрибутов вершин Для каждой вершины формируются:

    • позиция (position);
    • цвет (color, опционально);
    • UV-координаты (uv, при использовании текстуры).
  3. Шейдерная отрисовка В фрагментном шейдере происходит выборка текстуры:

    • используется sampler2D;
    • координаты интерполируются по треугольнику;
    • итоговый цвет вычисляется как комбинация текстуры и параметров слоя.

Подключение текстуры к PolygonLayer

Текстура задаётся через параметр image или через кастомные свойства материала слоя.

Пример базовой конфигурации:

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

const layer = new PolygonLayer({
  id: 'textured-polygons',
  data: polygons,
  getPolygon: d => d.coordinates,
  getFillColor: [255, 255, 255],
  image: 'https://example.com/texture.png',
  filled: true,
  stroked: false
});

В этом случае изображение используется как глобальная текстура, которая накладывается на все полигоны слоя.


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

В PolygonLayer UV-координаты не всегда задаются вручную. Вместо этого используется автоматическая генерация, основанная на геометрии.

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

1. Нормализованные координаты bounding box

Каждый полигон масштабируется в единичный квадрат:

  • минимальные и максимальные координаты вычисляются;
  • вершины нормализуются в диапазон [0, 1];
  • текстура растягивается по всей площади.

Недостаток — искажения при вытянутых геометриях.


2. Географическая проекция

При использовании GeoJsonLayer и координатных систем вроде LNGLAT UV может быть привязан к географическим координатам:

  • долгота → U;
  • широта → V.

Такой подход сохраняет глобальную согласованность текстур, но приводит к растяжениям ближе к полюсам.


3. Тайловая проекция

Текстура повторяется по пространству с заданным масштабом:

  • используется repeat wrapping;
  • UV рассчитывается как position * scaleFactor;
  • поддерживается бесшовное повторение изображений.

Настройка повторяемости текстуры

Поведение текстуры контролируется параметрами WebGL sampler-а:

  • wrapS = REPEAT
  • wrapT = REPEAT
  • minFilter и magFilter влияют на сглаживание

В Deck.gl это обычно задаётся через textureParameters:

const layer = new PolygonLayer({
  id: 'repeating-texture',
  data,
  image: textureUrl,
  textureParameters: {
    [GL.TEXTURE_WRAP_S]: GL.REPEAT,
    [GL.TEXTURE_WRAP_T]: GL.REPEAT
  }
});

Текстуры и GeoJsonLayer

GeoJsonLayer расширяет PolygonLayer и добавляет поддержку сложных геометрий. Текстурирование в нём работает аналогично, но с дополнительными этапами обработки:

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

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


Кастомные шейдеры для текстурирования

Для более сложного контроля применяется getShaderModule или extensions.

Фрагментный шейдер может переопределять поведение выборки:

uniform sampler2D texture;
varying vec2 vUV;

void main() {
  vec4 texColor = texture2D(texture, vUV);

  gl_FragColor = vec4(texColor.rgb * 0.8, texColor.a);
}

Возможные модификации:

  • цветовая коррекция текстуры;
  • наложение градиентов;
  • маскирование по атрибутам;
  • смешивание с data-driven color.

Динамическое текстурирование

Deck.gl позволяет использовать разные текстуры для разных объектов:

getTexture: d => d.textureUrl

В этом случае каждая геометрия может иметь собственный image.

Особенности реализации:

  • создаётся texture atlas или набор GPU-текстур;
  • происходит кеширование загрузки изображений;
  • важно учитывать лимиты WebGL контекста.

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

Для повышения производительности используется texture atlas — единое изображение, содержащее множество под-текстур.

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

  • снижение числа WebGL bind операций;
  • уменьшение переключений состояния GPU;
  • ускорение рендеринга больших наборов полигонов.

UV в этом случае рассчитываются с учётом смещения:

u' = u * scaleX + offsetX
v' = v * scaleY + offsetY

Прозрачность и смешивание текстур

При наложении текстур важную роль играет blending:

  • premultiplied alpha;
  • additive blending для световых эффектов;
  • multiplicative blending для затемнения.

Deck.gl использует стандартные WebGL режимы:

  • SRC_ALPHA / ONE_MINUS_SRC_ALPHA для обычной прозрачности;
  • ONE / ONE для усиления свечения.

Искажения и проблемы отображения

Типичные проблемы текстурирования полигонов:

Растяжение текстуры

Возникает при неравномерной геометрии. Решается:

  • применением тайлинга;
  • разбиением полигона;
  • использованием географических UV.

Артефакты швов

Появляются при повторяющихся текстурах:

  • неправильный wrap mode;
  • отсутствие padding в атласе;
  • фильтрация mipmap.

Низкая чёткость

Причины:

  • отсутствие mipmapping;
  • слишком маленькая текстура;
  • неправильный magFilter.

Производительность при текстурировании

Текстуры увеличивают нагрузку на GPU, особенно при большом количестве полигонов.

Оптимизационные стратегии:

  • использование одного общего изображения для всех объектов;
  • минимизация уникальных текстур;
  • кеширование загруженных ресурсов;
  • снижение разрешения текстур для дальних зумов;
  • использование binary attributes для ускорения передачи данных.

Масштабирование текстур в зависимости от зума

В геопространственных приложениях текстуры часто адаптируются к уровню масштаба:

  • на малом зуме используется упрощённая текстура;
  • на большом — детализированная;
  • переход осуществляется через LOD-механизм.

UV может модифицироваться как функция zoom:

uv = position * 2^zoomFactor

Интеграция с освещением и материалами

Хотя PolygonLayer по умолчанию не является физически корректным рендерером материалов, текстуры могут комбинироваться с освещением:

  • нормали используются для directional light;
  • текстура влияет на albedo;
  • цвет слоя модифицирует итоговый материал.

В более сложных сценах применяется комбинирование с LightingEffect.


Многослойное текстурирование

Deck.gl поддерживает наложение нескольких слоёв:

  • базовый слой — текстура;
  • второй слой — цветовые маски;
  • третий слой — границы или интерактивные подсветки.

Композиция выполняется через порядок рендеринга и blending state.


Практика построения сложных поверхностей

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

  • имитации типов покрытия (лес, вода, асфальт);
  • визуализации плотности данных;
  • отображения спутниковых снимков;
  • наложения heatmap-подобных паттернов.

Каждый случай требует настройки UV и blending под конкретную задачу визуализации.