Шейдерные модули в deck.gl представляют собой систему переиспользуемых GLSL-компонентов, которые встраиваются в вершинные и фрагментные шейдеры слоёв. Они позволяют декомпозировать графическую логику на независимые блоки, стандартизировать общие операции (проекция, освещение, picking) и обеспечивать согласованность между различными слоями визуализации.
В отличие от монолитных шейдеров, где вся логика сосредоточена в одном файле, модульная система строится вокруг композиции функций, uniform-переменных и препроцессорных директив, которые автоматически инжектируются в итоговый GLSL-код слоя.
Каждый шейдерный модуль в deck.gl — это JavaScript-объект, описывающий набор GLSL-фрагментов и метаданных. Он может содержать:
name — уникальное имя модуляvs — код, добавляемый в vertex shaderfs — код, добавляемый в fragment shaderuniforms — описание uniform-переменныхdefines — препроцессорные флагиinject — точки вставки кода в стандартные шаблоны
шейдеровМодули объединяются в массив и передаются в слой через свойство
modules.
import {ScatterplotLayer} from '@deck.gl/layers';
const layer = new ScatterplotLayer({
id: 'points',
data: dataset,
getPosition: d => d.position,
getRadius: d => d.radius,
modules: [project32, picking]
});
Deck.gl использует систему сборки шейдеров на этапе компиляции слоя. Каждый модуль проходит процесс:
vs и fs фрагментовuniforms и definesКлючевой механизм — предотвращение конфликтов имён. Для этого используется:
Один из базовых модулей — project. Он отвечает за
преобразование координат из географических или мировых систем в
clipspace.
Он поддерживает:
Типичный набор функций:
project_position(vec3 position)project_scale(float value)project_normal(vec3 normal)Внутренне модуль использует матрицы:
и вычисляет итоговое положение вершины:
vec4 position_world = modelMatrix * vec4(position, 1.0);
vec4 position_clip = projectionMatrix * viewMatrix * position_world;
Модуль picking обеспечивает поддержку интерактивности:
hover, click, selection.
Он добавляет:
picking colorВ vertex shader передаётся:
attribute vec3 instancePickingColor;
varying vec3 vPickingColor;
В fragment shader:
gl_FragColor = vec4(vPickingColor, 1.0);
При рендере в picking-pass вместо цветового буфера формируется
ID-buffer, который затем читается CPU-частью через
readPixels.
Lighting module используется в 3D-слоях (например,
MeshLayer, SimpleMeshLayer).
Поддерживает:
Основная функция:
vec3 calculateLighting(vec3 normal, vec3 position, vec3 color) {
vec3 lightDir = normalize(light.direction);
float diffuse = max(dot(normal, lightDir), 0.0);
return color * (ambient + diffuse);
}
Модуль может быть расширен через дополнительные источники света, передаваемые через uniform-массивы.
Модуль fp64 реализует high-precision вычисления
координат с использованием техники double-float emulation.
Так как WebGL не поддерживает double precision, применяется разложение числа:
struct vec2 {
float x;
float y;
};
Операции выполняются через алгоритмы компенсации ошибки:
Используется в глобальных визуализациях (карты, GIS-данные), где критична точность на больших масштабах.
Deck.gl позволяет модулям внедрять код в заранее определённые точки базового шейдера.
Примеры точек:
vs:#decl — объявления в vertex shadervs:#main-startfs:#declfs:#main-endПример:
const myModule = {
name: 'customEffects',
inject: {
'fs:#main-end': `
gl_FragColor.rgb *= 0.8;
`
}
};
Такой механизм позволяет изменять поведение слоя без переписывания всего шейдера.
Uniform-переменные в модулях описываются декларативно:
uniforms: {
opacity: 1.0,
intensity: {value: 0.5, type: 'f'}
}
Deck.gl автоматически:
В GLSL:
uniform float opacity;
Модули проектируются как независимые единицы, но часто используются вместе.
Пример типичного набора для 2D слоя:
project32pickingdirlight (если поддерживается освещение)Порядок подключения имеет значение только при конфликте
inject-точек.
Создание собственного модуля требует определения структуры GLSL и JS-обёртки.
Пример базового модуля:
export const grayscaleModule = {
name: 'grayscale',
fs: `
vec3 applyGrayscale(vec3 color) {
float g = dot(color, vec3(0.299, 0.587, 0.114));
return vec3(g);
}
`,
inject: {
'fs:#main-end': `
gl_FragColor.rgb = applyGrayscale(gl_FragColor.rgb);
`
}
};
Использование:
new ScatterplotLayer({
data,
modules: [project32, picking, grayscaleModule]
});
Шейдерные модули могут расширять набор vertex attributes слоя:
Пример:
attribute float instanceIntensity;
varying float vIntensity;
Передача:
vIntensity = instanceIntensity;
Это позволяет добавлять новые измерения данных без изменения базового слоя.
Модульность увеличивает гибкость, но влияет на:
Оптимизации:
В высоконагруженных сценах критично избегать избыточного числа модулей с перекрывающейся функциональностью.
Конфликты имен функций возникают при использовании нескольких кастомных модулей без неймспейсов. Решаются через явное префиксирование.
Ошибки компиляции часто связаны с:
Особенность архитектуры deck.gl — строгая синхронизация CPU/GPU слоёв: любое изменение модулей требует пересборки шейдера слоя, что может влиять на динамические обновления сцены.