Разработка игр
Шейдеры для игр
2001 год. Xbox запускает с Halo - первой консольной игрой с vertex shaders. Разработчики осознали: GPU - это не «быстрый растеризатор», а программируемый параллельный процессор. С тех пор шейдеры вышли далеко за пределы «затенения» - они делают физику, AI и ML inference прямо в браузере.
- Unreal Engine 5 Nanite/Lumen: compute shaders для virtual shadow maps и global illumination в реальном времени
- Unity DOTS: Job System + Burst Compiler + compute для физики с миллионами объектов
- WebGPU: compute shaders в браузере - Transformers.js запускает LLM inference на GPU пользователя
- Minecraft RTX: ray tracing через DXR compute pipeline - каждый луч это отдельный compute thread
Vertex shader: трансформация геометрии
**2001 год. Xbox запускает с Halo. Первая консольная игра с vertex shaders.** Разработчики осознали: GPU - это не «быстрый растеризатор», а программируемый параллельный процессор. Vertex shader запускается один раз для каждой вершины. Главная задача - трансформировать позицию через цепочку пространств: Model (локальные координаты объекта) → World (позиция в сцене) → View (относительно камеры) → Clip (проекция на экран). Кроме позиции, шейдер передаёт во fragment stage интерполированные varying-переменные: нормали, UV-координаты, tangent-векторы для normal mapping.
**Displacement mapping vs normal mapping**: vertex shader может двигать вершины по normal - displacement mapping. Высота читается из текстуры: `position += normal * texture(heightMap, uv).r * scale`. Результат - реальные геометрические детали. Normal mapping дешевле (только иллюзия в fragment stage), но displacement создаёт корректный силуэт и тени.
В Unreal Engine 5 Nanite vertex shader фактически заменён системой виртуальной геометрии: меш делится на микрополигональные кластеры, и только видимые кластеры попадают в pipeline. Результат - Nanite меш из 10M треугольников рендерится быстрее чем обычный меш из 100K.
Vertex shader трансформирует позицию вершины. В какое финальное пространство должна попасть gl_Position?
Fragment shader: PBR материалы и текстуры
**RTX 4090: 16 384 shader cores. Fragment shader выполняется для каждого пикселя каждого кадра.** При 4K 60 fps: 3840×2160×60 = 498 млн вызовов в секунду. Fragment shader получает интерполированные varying-переменные от vertex stage и вычисляет финальный цвет пикселя. Современные игры используют Physically Based Rendering (PBR): материал описывается через albedo (базовый цвет), metallic (металличность), roughness (шероховатость). Уравнение освещения - Cook-Torrance BRDF с GGX normal distribution.
**Early-Z culling**: GPU может отклонять фрагменты до запуска fragment shader, если глубина уже известна из предыдущего z-prepass. В Unreal Engine depth prepass рендерит только глубину первым проходом - потом основной G-buffer pass экономит ~40% вызовов fragment shader за счёт early-Z rejection.
Alpha blending ломает early-Z: полупрозрачные объекты не пишут в depth buffer и должны рендериться после opaque геометрии, отсортированной back-to-front. Поэтому в играх transparent меши (стекло, вода) всегда отдельный render pass.
PBR материал в fragment shader описывается тремя ключевыми параметрами. Что контролирует параметр roughness?
Post-processing: full-screen эффекты
**Bloom делает изображение хуже физически, но воспринимается как более реалистичное.** Человеческий глаз знает как выглядит bloom от яркого источника - и мозг интерпретирует его как свидетельство высокой яркости. Post-processing работает через технику full-screen quad: сцена рендерится в texture (render-to-texture), затем quad покрывает весь экран и fragment shader читает эту текстуру как input. Цепочка эффектов в Unreal Engine - это стек render passes, каждый читает output предыдущего.
**Motion Blur через velocity buffer**: для корректного motion blur каждый пиксель должен знать свою скорость движения на экране. Это реализуется через velocity buffer - отдельный render target где rg = скорость пикселя в texel/frame. Motion blur pass размазывает цвет вдоль velocity вектора. Результат - кинематографический эффект скорости без артефактов смазывания статичных объектов.
FXAA (Fast Approximate Anti-Aliasing) - post-process сглаживание: находит края по luminance градиенту и блюрит вдоль края. Работает в один проход за ~0.3ms. DLSS/FSR - нейросетевое масштабирование как post-process: рендер в 1080p, апскейл в 4K с реконструкцией деталей.
Bloom эффект реализуется через несколько render passes. Какой правильный порядок?
Compute shaders: GPU как параллельный процессор
**Шейдер - это не «программа для теней». Слово shader от shade (затенение). Но compute shaders делают физику, AI pathfinding и обработку аудио.** Название устарело. Compute shader работает без растеризации: нет вершин, нет фрагментов, нет render target - только произвольные вычисления на GPU. Запуск через dispatch(X, Y, Z): X*Y*Z workgroups, каждая по N threads. Внутри workgroup потоки делят shared memory (~48 KB) и могут синхронизироваться через barrier(). Применение: симуляция 1M частиц, GPU culling, AI inference.
**WebGPU и ML inference в браузере**: compute shaders доступны в браузере через WebGPU API (Chrome 113+). Transformers.js использует WebGPU compute для запуска языковых моделей: WGSL compute шейдеры выполняют матричное умножение на GPU пользователя без серверных затрат. Модель Phi-3 Mini (3.8B параметров) работает в браузере на RTX при ~15 tokens/sec.
Metal Performance Shaders (MPS) на Apple Silicon: GPU-ускоренный ML без CUDA. Core ML компилирует нейросеть в compute шейдеры Metal. На M3 Pro нейросетевой движок (ANE) + GPU работают параллельно - ANE для стандартных операций, GPU compute для нестандартных.
Compute shaders требуют CUDA и видеокарты NVIDIA
Compute shaders поддерживаются в HLSL (DirectX 11+), GLSL (OpenGL 4.3+), WGSL (WebGPU), Metal - на любом современном GPU включая интегрированные
CUDA - проприетарная платформа NVIDIA. Стандартные графические API давно имеют compute: DirectCompute с 2009 года, OpenGL compute с 2012, Metal с 2014, Vulkan с 2016, WebGPU с 2023. AMD, Intel, Apple GPU полностью поддерживают compute шейдеры через эти API
Compute shader запускается через dispatch(64, 1, 1) с local_size_x = 256. Сколько всего потоков будет запущено?
Ключевые идеи
- **Vertex shader** трансформирует геометрию через Model→World→View→Clip пространства и передаёт varying-переменные во fragment stage. Skinning анимация - линейное смешивание матриц костей прямо в vertex shader
- **Fragment shader** вычисляет цвет пикселя: читает текстуры, применяет PBR освещение (Cook-Torrance GGX), смешивает terrain слои по splat map. Early-Z culling отсеивает невидимые фрагменты до запуска шейдера
- **Post-processing** работает через full-screen quad и render-to-texture: Bloom (bright pass + blur + composite), Chromatic Aberration, Motion Blur по velocity buffer, FXAA сглаживание
- **Compute shaders** - GPGPU без растеризации: симуляция частиц, GPU frustum culling, ML inference. Работают на любом современном GPU через HLSL/GLSL/Metal/WGSL - CUDA не нужна
Связанные темы
Шейдеры - точка пересечения графики, параллельных вычислений и ML:
- 3D рендеринг в играх — Шейдеры - программируемые стадии render pipeline из предыдущего урока
- Компьютерная графика — Математика за шейдерами: матричные трансформации, BRDF модели освещения
- Параллельные вычисления — Compute shaders - SIMD/SPMD модель выполнения на GPU, аналог CUDA GPGPU
- AR/VR разработка — Foveated rendering и lens distortion шейдеры - специфика VR pipeline
Вопросы для размышления
- Vertex shader выполняется параллельно для всех вершин - почему важно что каждый поток независим и не видит данные соседних вершин? Как это ограничение влияет на дизайн grass wave анимации?
- Bloom физически некорректен (реальный bloom - дефект линзы), но делает изображение «реалистичнее». Какие ещё post-processing эффекты существуют только как имитация перцептивных артефактов, а не физических явлений?
- GPU culling через compute shader позволяет GPU самостоятельно решать что рендерить. Как это изменяет архитектуру CPU-GPU взаимодействия по сравнению с классическим подходом где CPU готовит список draw calls?