Компьютерная графика
Линейная алгебра для графики
Цели урока
- Вычислять dot и cross product и понимать их геометрический смысл
- Строить матрицы поворота, масштаба и перемещения
- Понимать почему порядок TRS критичен и читать матрицы справа налево
- Работать с однородными координатами и матрицами 4x4
Предварительные знания
Pixar 'Toy Story' 1995: первый полнометражный CGI-фильм. 800 000 часов рендеринга на ферме из 117 Sun SparcStation. Сегодня: Unreal Engine 5 Nanite - реалтайм рендеринг миллиарда полигонов. 30 лет - от 800K часов до 60FPS в реальном времени. Разница в одном: та же линейная алгебра, только на GPU.
- **Unity/Unreal Engine:** Transform каждого объекта - TRS-матрица 4x4. GPU применяет её ко всем вершинам меша одновременно
- **NVIDIA RTX 4090:** 82.6 терафлоп - буквально миллиарды умножений 4x4 матриц каждую секунду
- **Робототехника:** кинематика руки Boston Dynamics - цепочка 4x4 матриц, каждый сустав это rotation + translation
- **AR/VR (Apple Vision Pro):** трекинг положения головы в реальном времени - view-матрица. Задержка 10+ мс -> brain rejects it как tearing
- **Stable Diffusion / NeRF:** 3D-сцена кодируется как матрица трансформаций - те же 4x4
Иван Сазерленд и рождение компьютерной графики
В 1963 году аспирант MIT Иван Сазерленд защитил диссертацию и представил **Sketchpad** - первую в мире интерактивную графическую программу. Первый GUI, первый direct manipulation, первое применение матриц трансформаций для 2D-объектов. Сазерленд нарисовал то, что сейчас живёт в каждом GPU: иерархия объектов + матрицы трансформаций. В 1988 получил премию Тьюринга.
Векторы: dot и cross product
Pixar, 1995. **Toy Story** - первый полнометражный CGI-фильм. 800 000 часов рендеринга на ферме из 117 Sun SparcStation. Сегодня Unreal Engine 5 Nanite гонит реалтайм рендеринг миллиарда полигонов на одной видеокарте. 30 лет - от 800K часов до 60FPS. Разница в одном: **линейная алгебра на GPU**.
**Вектор** в 3D - тройка (x, y, z). Два ключевых произведения: **dot product** a·b = |a||b|cos(theta) (скаляр, показывает угол между векторами), **cross product** a x b = нормальный вектор к плоскости (вектор, показывает ориентацию).
| Операция | Результат | Применение в графике |
|---|---|---|
| a · b (dot) | Скаляр | Phong shading (cos угла), frustum culling, FOV |
| a x b (cross) | Вектор, перп. a и b | Нормали треугольников, backface culling |
| |a| (length) | Скаляр | Расстояние между точками, нормализация |
| normalize(a) | Единичный вектор | Направления: камера, источник света, шейдеры |
**Dot product** отвечает на вопрос «насколько два вектора сонаправлены» (> 0 - острый угол, = 0 - перпендикулярны, < 0 - тупой угол). Именно это используется в шейдере Phong: яркость пикселя = max(0, dot(normal, light)). **Cross product** даёт ориентацию поверхности - без него нет нормалей, нет освещения, нет 3D-графики.
Dot product двух единичных векторов равен 0. Что это означает геометрически?
Матрицы и их умножение
Вектор описывает точку или направление. **Матрица** описывает **трансформацию** - как изменить вектор: повернуть, масштабировать, спроецировать. Умножение матрицы на вектор - применение трансформации. Каждая вершина в 3D-сцене проходит через несколько таких умножений за каждый кадр.
**Матрица** NxM - таблица чисел. В графике: 3x3 для линейных трансформаций, 4x4 для аффинных (с переносом). Умножение A(m x n) на v(n x 1) даёт u(m x 1). Ключевое: матрицы можно **перемножать** - цепочка трансформаций схлопывается в одну.
**Композиция трансформаций** - умножение матриц. M1 - поворот, M2 - масштаб, то M2 @ M1 - сначала поворот, потом масштаб. Одна матрица заменяет всю цепочку. Это не просто удобство - это то, что позволяет GPU применять тысячи вершин через один shader-call.
**Умножение матриц НЕ коммутативно!** A x B != B x A. Rotate-then-Scale даёт другой результат, чем Scale-then-Rotate. Это источник сотен багов в движках каждый год.
| Свойство | Верно? | Значение для графики |
|---|---|---|
| A x B = B x A (коммутативность) | Нет! | Порядок трансформаций критичен |
| (A x B) x C = A x (B x C) (ассоциативность) | Да | Предвычислить M = A x B x C заранее |
| I x A = A (единичная) | Да | I - нет трансформации (identity) |
| A x A^-1 = I (обратная) | Да (если существует) | View matrix = inverse(camera TRS) |
Матрица M = R x S (R - поворот, S - масштаб). При применении M x v, что происходит ПЕРВЫМ?
Базовые трансформации: TRS
Три базовые трансформации: **Translation** (перемещение), **Rotation** (вращение), **Scale** (масштабирование). В Unity, Unreal, Blender - каждый Transform компонент это TRS. Каждый GameObject, каждый меш, каждая камера описываются этой тройкой.
**TRS** - стандартный порядок: Translation x Rotation x Scale. Сначала масштабируем (S), потом поворачиваем (R), потом перемещаем (T). Читаем справа налево. Это не конвенция - это единственный порядок, при котором Scale не искажает Translation.
Но **перемещение (translation)** нельзя выразить через матрицу 3x3. Сложение (x + tx, y + ty, z + tz) - не линейная операция. Для этого нужен переход к **однородным координатам** и матрицам 4x4.
| Трансформация | Матрица 3x3? | Матрица 4x4? | Свойство |
|---|---|---|---|
| Scale | Да | Да | Линейная |
| Rotation | Да | Да | Линейная, сохраняет длины |
| Translation | Нет! | Да | Аффинная (не линейная) |
| Perspective projection | Нет! | Да | Нелинейная (деление на w) |
Объект масштабирован в 2 раза (S), повёрнут на 90° (R), перемещён на (3,0,0) (T). Как записать матрицу?
Однородные координаты и 4x4 матрицы
Масштабирование и вращение - линейные операции (v' = M x v). Перемещение - нет (v' = v + t). Как объединить всё в единую матрицу? **Однородные координаты**: добавляем четвёртую координату **w**, и перемещение становится умножением на матрицу 4x4.
**Однородные координаты** - представление 3D-точки (x, y, z) как (x, y, z, 1) в 4D. w = 1 для точек, w = 0 для направлений (векторов). Матрица 4x4 кодирует translation, rotation, scale и projection в одном умножении - это то, что выполняет vertex shader.
Трюк с w = 0 для векторов: перемещение не влияет на направления. Физически корректно: нормаль поверхности «вправо» остаётся «вправо» независимо от того, куда переместился объект. Шейдеры опираются на это при расчёте освещения.
| w-координата | Тип | Translation влияет? | Пример |
|---|---|---|---|
| w = 1 | Точка (position) | Да | Вершина меша, позиция камеры |
| w = 0 | Направление (vector) | Нет | Нормаль, direction of light |
| w != 0, 1 | После projection | - | Perspective divide: (x/w, y/w, z/w) |
Каждый кадр каждой 3D-игры - миллионы умножений 4x4 матриц на 4D-векторы. RTX 4090 выполняет 82.6 терафлоп. Однородные координаты объединяют весь пайплайн (TRS + view + projection) в цепочку матричных умножений. Без этой математики нет ни Cyberpunk, ни Avatar.
Порядок трансформаций (TRS vs SRT) не важен - результат одинаковый
Порядок критически важен! TRS: сначала Scale, потом Rotate, потом Translate (читаем справа налево). SRT: сначала Translate, потом Rotate, потом Scale. Результаты совершенно разные, потому что Scale масштабирует и Translation-компонент.
Матричное умножение некоммутативно: A x B != B x A. При SRT масштабирование применяется после перемещения, что искажает позицию объекта. При TRS масштабирование первое, перемещение последнее - и не искажается.
Вектор направления (1, 0, 0) записан как (1, 0, 0, 0). Что произойдёт при умножении на матрицу перемещения T?
Ключевые идеи
- **Dot product** = cos(угла) * длины. Основа Phong lighting, backface culling, FOV
- **Cross product** = перпендикулярный вектор. Основа нормалей, ориентации треугольников
- **Матрицы 4x4** в однородных координатах объединяют TRS + projection в одно умножение
- **Порядок TRS критичен:** Scale - Rotate - Translate (читаем справа налево). A x B != B x A
- **w = 1** для точек (translation влияет), **w = 0** для направлений (translation не влияет)
- **Perspective divide:** деление на w создаёт эффект перспективы - дальние объекты меньше
Связанные темы
Линейная алгебра - язык всей 3D-графики:
- Растеризация и пиксели — Результат трансформаций (вершины в screen space) подаётся на растеризатор
- Координатные пространства — Матрицы TRS, View, Projection - переходы model->world->view->clip
- Вычислительная геометрия — Cross product, ориентация - общий фундамент с comp. geometry
Вопросы для размышления
- Почему GPU оптимизированы для умножения 4x4 матриц, а не произвольных размеров?
- Кватернионы (quaternions) часто используются вместо матриц для вращения. Какие преимущества они дают?
- Как реализовать поворот объекта вокруг произвольной точки (не начала координат)?
Связанные уроки
- cg-01 — Растеризация и screen space вводятся в предыдущем уроке
- cg-03 — Координатные пространства model/world/view/clip - прямое следствие TRS и 4x4
- cgeom-01 — Cross product и orientation - общий фундамент с вычислительной геометрией
- la-06-transformations — Полная теория линейных отображений и change-of-basis
- arch-15-gpu-architecture — GPU оптимизированы именно под умножение 4x4 матриц на 4D-векторы
- la-05-matrices-intro — Базовые операции с матрицами если нужно освежить