GLSL (OpenGL Shading Language) представляет собой язык программирования шейдеров, исполняемых на GPU в рамках графического конвейера WebGL. В экосистеме CesiumJS GLSL используется для описания поведения вершин и пикселей при рендеринге глобуса, 3D-тайлов, примитивов и пользовательских визуальных эффектов.
Шейдеры разделяются на два ключевых типа: вершинные (vertex) и
фрагментные (fragment). В CesiumJS они применяются для кастомизации
материалов, постобработки, а также расширения стандартного визуального
пайплайна через Custom Shader и низкоуровневые
GLSL-фрагменты.
GPU-пайплайн состоит из последовательных стадий обработки геометрии:
GLSL задействуется на двух стадиях:
Vertex Shader
Fragment Shader
CesiumJS добавляет собственные соглашения и утилитарные функции,
начинающиеся с префикса czm_, упрощающие работу с
координатами и матрицами.
Типичный фрагментный шейдер имеет следующую форму:
precision highp float;
uniform sampler2D u_texture;
varying vec2 v_uv;
void main() {
vec4 color = texture2D(u_texture, v_uv);
gl_FragColor = color;
}
Ключевые элементы:
precision — точность вычисленийuniform — глобальные параметры, одинаковые для всех
вызовов шейдераvarying — данные, интерполируемые между vertex и
fragment стадиямиgl_FragColor — итоговый цвет пикселя (в WebGL1)GLSL использует строгую типизацию:
Скалярные типы
floatintboolВекторные типы
vec2, vec3, vec4ivec2, ivec3, ivec4bvec2, bvec3, bvec4Матрицы
mat2, mat3, mat4Пример:
vec3 position = vec3(1.0, 2.0, 3.0);
mat4 transform = mat4(1.0);
GLSL предоставляет встроенную поддержку математических операций над векторами:
vec3 a = vec3(1.0, 2.0, 3.0);
vec3 b = vec3(3.0, 2.0, 1.0);
vec3 sum = a + b;
vec3 scaled = a * 2.0;
float dotProduct = dot(a, b);
vec3 crossProduct = cross(a, b);
Компоненты вектора доступны через swizzling:
vec4 color = vec4(1.0, 0.5, 0.2, 1.0);
vec3 rgb = color.rgb;
float alpha = color.a;
Uniform-значения передаются из JavaScript-кода в шейдер:
Пример концептуального использования:
uniform mat4 u_modelViewMatrix;
uniform mat4 u_projectionMatrix;
uniform float u_time;
CesiumJS автоматически предоставляет множество системных uniform-переменных, включая матрицы координатных преобразований и параметры сцены.
Varying-переменные обеспечивают интерполяцию данных между вершинным и фрагментным шейдером:
Vertex shader:
varying vec2 v_uv;
void main() {
v_uv = uvCoordinates;
}
Fragment shader:
varying vec2 v_uv;
void main() {
gl_FragColor = vec4(v_uv, 0.0, 1.0);
}
Работа с GLSL в CesiumJS тесно связана с множеством пространств координат:
Матрицы трансформации выполняют переходы между ними:
gl_Position = czm_projection * czm_view * czm_model * vec4(position, 1.0);
czm_projection, czm_view,
czm_model — стандартные матрицы CesiumJS.
Точность вычислений критична для мобильных GPU:
precision highp float;
precision mediump int;
lowp — низкая точность, высокая производительностьmediump — балансhighp — максимальная точностьВ географических сценах CesiumJS высокая точность используется для избежания артефактов при больших координатах.
GLSL включает широкий набор математических функций:
Тригонометрия
sin(angle)
cos(angle)
tan(angle)
Математические операции
abs(x)
min(a, b)
max(a, b)
clamp(x, 0.0, 1.0)
Интерполяция
mix(a, b, t)
smoothstep(edge0, edge1, x)
CesiumJS расширяет GLSL набором встроенных функций:
czm_transformPointczm_inverseViewczm_viewczm_projectionczm_normalПример использования:
vec4 eyePosition = czm_view * vec4(position, 1.0);
Такие функции обеспечивают корректную работу с эллипсоидальной моделью Земли и глобальной системой координат.
Фрагментный шейдер часто реализует модель освещения:
vec3 normal = normalize(v_normal);
vec3 lightDir = normalize(u_lightPosition - v_position);
float diff = max(dot(normal, lightDir), 0.0);
vec3 diffuse = diff * u_color;
Модель освещения может расширяться до Phong или PBR-подходов, используемых в более сложных материалах CesiumJS.
Текстуры загружаются как sampler2D:
uniform sampler2D u_texture;
vec4 texColor = texture2D(u_texture, v_uv);
UV-координаты обычно передаются из вершинного шейдера и интерполируются.
GLSL поддерживает условные конструкции, но их использование в GPU требует осторожности:
if (diff > 0.5) {
color = vec3(1.0);
} else {
color = vec3(0.0);
}
Избыточные ветвления могут снижать производительность из-за SIMD-архитектуры GPU.
Циклы допустимы, но часто требуют статической развёртки:
for (int i = 0; i < 5; i++) {
sum += values[i];
}
Динамические циклы ограничены или не поддерживаются в зависимости от GPU и WebGL версии.
Пульсация цвета по времени
float pulse = sin(u_time * 2.0) * 0.5 + 0.5;
vec3 color = mix(vec3(0.0, 0.2, 1.0), vec3(1.0, 0.8, 0.0), pulse);
Высотное окрашивание
float heightFactor = clamp(v_position.z / 10000.0, 0.0, 1.0);
vec3 color = mix(vec3(0.0, 0.3, 0.6), vec3(0.2, 1.0, 0.4), heightFactor);
Типичные проблемы GLSL в CesiumJS:
Отладка часто сводится к визуализации промежуточных значений через цветовые каналы:
gl_FragColor = vec4(v_normal * 0.5 + 0.5, 1.0);