Язык GLSL: типы и функции

GLSL — язык шейдеров, похожий на C, но со встроенными векторами, матрицами и быстрыми графическими функциями.

GLSL (OpenGL Shading Language) — язык, на котором пишут вершинные и фрагментные шейдеры; в нём векторы и матрицы — встроенные типы.

Зачем это знать

В графике вектор из 3–4 чисел — повсюду: позиция, цвет, нормаль. GLSL делает работу с ними естественной: сложение векторов, скалярное и векторное произведение, нормализация — встроены и считаются аппаратно. Знание типов и квалификаторов — это азбука написания шейдеров.

Векторные и матричные типы

ТипЧто это
floatчисло с плавающей точкой
vec2/vec3/vec4вектор из 2/3/4 float
mat3/mat4матрица 3×3 / 4×4
sampler2Dдескриптор текстуры

У вектора компоненты доступны как .x .y .z .w или как цвет .r .g .b .a. Можно «тасовать» их — это swizzling: color.rgb, pos.xy, v.xxy.

Квалификаторы каналов данных

КвалификаторНазначение
attribute (in)данные на вершину: позиция, нормаль, UV
uniformодинаков для всех вершин/пикселей вызова: матрицы, время, текстуры
varying (out/in)из вершинного во фрагментный, интерполируется

Встроенные функции — на Python-аналогах

Чтобы прочувствовать встроенные функции GLSL, воспроизведём три из них на stdlib Python: clamp, mix, step.

def clamp(x, lo, hi):
    return max(lo, min(x, hi))

def mix(a, b, t):
    return a + (b - a) * t

def step(edge, x):
    return 0.0 if x < edge else 1.0

print("clamp(1.5, 0, 1):", clamp(1.5, 0, 1))
print("clamp(-0.2, 0, 1):", clamp(-0.2, 0, 1))
print("mix(0, 10, 0.3):", mix(0, 10, 0.3))
print("step(0.5, 0.4):", step(0.5, 0.4))
print("step(0.5, 0.6):", step(0.5, 0.6))

Вывод:

clamp(1.5, 0, 1): 1
clamp(-0.2, 0, 1): 0
mix(0, 10, 0.3): 3.0
step(0.5, 0.4): 0.0
step(0.5, 0.6): 1.0

clamp зажимает значение в диапазон, mix смешивает, step даёт резкую границу 0/1 — это рабочие лошадки шейдеров для эффектов и масок.

Маленький осмысленный GLSL

precision mediump float;
uniform float uTime;     // время, обновляется каждый кадр
varying vec2 vUV;
void main() {
    float pulse = 0.5 + 0.5 * sin(uTime);     // 0..1, пульсирует
    vec3 base = vec3(vUV, 0.5);               // цвет из координат
    vec3 col = mix(base, vec3(1.0), pulse);   // мигание к белому
    gl_FragColor = vec4(col, 1.0);
}

Как работает под капотом

Векторные операции GLSL покомпонентны: a + b для vec3 складывает по координатам, a * b — тоже покомпонентно (а не скалярное произведение — для него есть dot). GPU исполняет такие операции над всеми компонентами параллельно одной инструкцией. Swizzling бесплатен — это просто переадресация компонент.

Частые ошибки

  • Думать, что vec3 * vec3 — скалярное произведение; это покомпонентное умножение, dot — отдельно.
  • Менять uniform «на каждый пиксель» — uniform постоянен в пределах вызова отрисовки.
  • Забывать precision во фрагментном шейдере на мобильных GPU (WebGL) — ошибка компиляции.

Итоги

  • GLSL: встроенные vec2/3/4, mat3/4, swizzling (.rgb, .xy).
  • attribute — на вершину, uniform — на вызов, varying — интерполируется.
  • clamp, mix, step, dot, normalize — базовые встроенные функции.
  • Операции над векторами покомпонентны; dot — отдельная функция.
Проверьте себя
1. Что такое swizzling в GLSL?
AСжатие текстур
BДоступ и перестановка компонент вектора, например color.rgb или pos.xy
CПоворот матрицы
DТип ошибки компиляции
2. Какой квалификатор означает данные, одинаковые для всех вершин и пикселей вызова?
Aattribute
Bvarying
Cuniform
Dsampler2D
3. Что вычисляет vec3(1,2,3) * vec3(2,2,2) в GLSL?
AСкалярное произведение 12
BПокомпонентное умножение (2,4,6)
CВекторное произведение
DОшибку