№1
Что такое WebGL
WebGL — JavaScript API для рисования на видеокарте.
Вы передаёте GPU вершины и две программы — шейдеры. GPU собирает из вершин треугольники и считает цвет каждого пикселя параллельно.
CPU
Несколько мощных ядер: сложная логика, задачи по очереди.
GPU
Тысячи простых ядер: одна программа для каждого пикселя одновременно.
Это не 3D-движок: сцен, камер и света нет. Только точки, линии, треугольники и шейдеры.
| Что | Как рисует | Когда брать |
|---|---|---|
| CSS 3D | трансформирует DOM-элементы | карточки, флипы, параллакс |
| Canvas 2D | 2D-фигуры по командам | графики, простые игры |
| WebGL | треугольники + шейдеры на GPU | 3D, тысячи объектов, эффекты |
| WebGPU | новый GPU API: рендер и вычисления | новые проекты, вычисления на GPU |
№2
Как это устроено
Конвейер: вершины → пиксели.
Вершинный шейдер считает положение каждой вершины. GPU находит пиксели внутри треугольника и для каждого запускает фрагментный шейдер — он возвращает цвет.
- Вершинымассив чисел в буфере
- Vertex shaderраз на вершину → позиция
- Растеризацияпиксели внутри треугольника
- Fragment shaderраз на пиксель → цвет
- Экранили текстура
attribute- данные каждой вершины (позиция, цвет) — как пропсы
uniform- одно значение на весь вызов (время, матрица) — как контекст
varying- из вершинного шейдера во фрагментный, с интерполяцией
texture- изображение или массив данных, читается по координатам
№3
Первый треугольник
Минимальная программа — пять шагов.
- 1
Контекст — все вызовы WebGL — методы этого объекта
canvas.getContext("webgl2") - 2
Шейдеры — исходник GLSL передаётся строкой
gl.shaderSource(shader, source) - 3
Программа — ошибки компиляции надо запрашивать явно
gl.linkProgram(program) - 4
Вершины — копируются в память GPU
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW) - 5
Отрисовка — три вершины — один треугольник
gl.drawArrays(gl.TRIANGLES, 0, 3)
№4
Мой первый шейдер
Фрагментный шейдер: (координата, время) → цвет.
Он выполняется для каждого пикселя независимо. Здесь цвет — косинус от координаты и времени, поэтому градиент движется.
#version 300 es
precision highp float;
uniform vec2 u_resolution;
uniform float u_time;
out vec4 outColor;
// Выполняется для каждого пикселя: координата + время → цвет.
void main() {
vec2 uv = gl_FragCoord.xy / u_resolution;
vec3 color = 0.5 + 0.5 * cos(u_time + uv.xyx + vec3(0.0, 2.0, 4.0));
outColor = vec4(color, 1.0);
}№5
Миллион точек
Миллион точек на графике — без тормозов.
В SVG и Canvas 2D каждая точка — отдельная команда от JavaScript, и так на каждом кадре. В WebGL точки один раз загружаются в видеопамять и рисуются одним вызовом, а зум и сдвиг — два uniform: позиции пересчитывает вершинный шейдер.
#version 300 es
in vec2 a_position; // точка данных, координаты −1..1
in float a_group; // сегмент: 0..3
uniform vec2 u_center; // центр вида в координатах данных
uniform vec2 u_scale; // зум с поправкой на пропорции окна
uniform float u_pointSize; // в пикселях буфера
uniform vec3 u_palette[4];
out vec3 v_color;
// Зум и сдвиг — два uniform: миллион позиций пересчитывает GPU,
// данные в видеопамяти не меняются.
void main() {
gl_Position = vec4((a_position - u_center) * u_scale, 0.0, 1.0);
gl_PointSize = u_pointSize;
v_color = u_palette[int(a_group)];
}→ колесо — зум к курсору, перетаскивание — сдвиг, двойной клик — сброс
№6
Шейдер поверх страницы
WebGL не видит DOM.
Шейдеру доступны только буферы и текстуры. Экспериментальный HTML-in-Canvas отрисовывает HTML внутри canvas в текстуру — с настоящими шрифтами, ховерами и выделением.
Поэтому вся страница здесь — внутри одного canvas, а окна — часть той же сцены: шейдер окна получает всё, что под ним.
r → r · (1 − k + k·r²)- Стекло — каждый осколок по-своему сдвигает и поворачивает изображение
- Рябь — смещение по наклону волновой поверхности
- Огонь — фрактальный шум, движущийся вверх, и цветовая шкала
→ откройте окна и поводите ими по странице и друг над другом
№7
Шейдеры из Winamp
Взял шейдеры из Winamp и встроил их сюда.
№8
Грабли
Ошибки WebGL не бросают исключений.
Один пульт на всех
Всё состояние
glглобальное. Забыл переключить буфер — рисуешь не тем.Ошибки молчат
Шейдер не собрался — исключения нет, только чёрный экран. Проверяйте
getShaderInfoLog.Вызовы дороже вершин
Один draw call на миллион треугольников быстрее тысячи мелких вызовов.
Мыло на ретине
Размер буфера canvas = CSS-размер ×
devicePixelRatio.Потеря контекста
При сбое драйвера ресурсы GPU пропадают. Обрабатывайте
webglcontextlost.
№9
Брать ли библиотеку
Сырой WebGL — как DOM API. Three.js — как React.
- Three.jsсцена, камера, свет, модели — стандарт де-факто
- React Three FiberThree.js как JSX-компоненты
- Babylon.jsдвижок «с батарейками»: физика, редактор, WebGPU
- PixiJSбыстрый 2D: спрайты и фильтры
- OGL / twglтонкие помощники — когда нужен почти сырой WebGL
→ один полноэкранный шейдер — сырой WebGL; появились камера и модели — библиотека
№10
Что почитать
- WebGL2 Fundamentals — лучший курс с нуля
- The Book of Shaders — как думать пикселями
- Shadertoy — тысячи шейдеров — смотреть и ломать
- MDN — WebGL API — справочник
- HTML-in-Canvas — то, на чём живёт эта тетрадь