Преобразования в компьютерной графике

Каждая трансформация фигуры на экране — это умножение её вершин на матрицу преобразования.

Геометрическое преобразование фигуры — это применение одной и той же матрицы ко всем её вершинам; форма меняется согласованно, потому что преобразование линейно.

Когда в игре или редакторе вы поворачиваете спрайт, движок не пересчитывает картинку «на глаз» — он умножает координаты вершин на матрицу поворота. Соберём раздел про матрицы воедино на практичном примере: повернём и масштабируем многоугольник.

Фигура как набор вершин

Квадрат — это четыре точки. Чтобы повернуть его на $90°$, применим матрицу поворота к каждой вершине. Композиция (например, повернуть и сразу растянуть) — это произведение матриц, посчитанное один раз и применённое ко всем точкам.

import math

def matvec(A, v):
    return [sum(A[i][j] * v[j] for j in range(len(v)))
            for i in range(len(A))]

def matmul(A, B):
    return [[sum(A[i][t] * B[t][j] for t in range(len(B)))
             for j in range(len(B[0]))] for i in range(len(A))]

rot90 = [[0, -1], [1, 0]]
scale2 = [[2, 0], [0, 2]]
T = matmul(scale2, rot90)   # сначала повернуть, потом увеличить

square = [[1, 0], [0, 1], [-1, 0], [0, -1]]
for p in square:
    print(p, "->", matvec(T, p))

Вывод:

[1, 0] -> [0, 2]
[0, 1] -> [-2, 0]
[-1, 0] -> [0, -2]
[0, -1] -> [2, 0]

Что произошло с квадратом

Каждая вершина повернулась на $90°$ и удвоилась по длине. Точка $(1, 0)$ уехала вверх в $(0, 2)$, $(0, 1)$ — влево в $(-2, 0)$. Квадрат повернулся и стал вдвое больше, оставшись квадратом — линейность сохранила форму. Матрицу $T$ мы посчитали один раз, а применили ко всем вершинам: в реальной графике так обрабатывают тысячи точек.

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

Реальные движки используют чуть больший приём — однородные координаты: к двумерной точке добавляют третью единичную координату, что позволяет уместить в одну матрицу $3 \times 3$ не только повороты и масштаб, но и параллельный перенос (который сам по себе не линеен). Тогда любую цепочку «повернуть, сдвинуть, масштабировать» сворачивают в одно матричное произведение и применяют к вершинам за один проход. Это объясняет, почему графические процессоры заточены именно под умножение матриц на векторы — это самая частая операция в рендеринге.

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

  • Перепутать порядок композиции. $T = S \cdot R$ означает «сначала $R$, потом $S$»; обратный порядок даст другой результат.
  • Применять преобразование к фигуре «целиком», а не к каждой вершине. Матрица действует на точки (векторы), а форма получается из их совокупности.
  • Пытаться задать параллельный перенос матрицей $2 \times 2$. Для этого нужны однородные координаты.

Итог

  • Преобразование фигуры = умножение каждой её вершины на матрицу.
  • Композицию преобразований сворачивают в одно матричное произведение.
  • Линейность сохраняет форму: квадрат остаётся квадратом, прямые — прямыми.
  • Однородные координаты позволяют включить и параллельный перенос в одну матрицу.
Проверьте себя
1. Как повернуть многоугольник на экране?
Aумножить каждую вершину на матрицу поворота
Bсложить все вершины
Cвзять определитель фигуры
Dподелить координаты на 2
2. Произведение T = S·R (S — масштаб, R — поворот) применяется к точке как:
Aсначала S, потом R
Bсначала R, потом S
Cодновременно
Dтолько S
3. Зачем в компьютерной графике используют однородные координаты (доп. координату)?
Aчтобы ускорить деление
Bчтобы включить параллельный перенос в матричное умножение
Cчтобы убрать повороты
Dэто лишняя сложность без пользы