Комбинирование преобразований
Реальный объект масштабируют, поворачивают и переносят — и порядок этих действий меняет результат.
Композиция преобразований — последовательное применение нескольких матриц, выражаемое их произведением; порядок умножения важен.
Зачем это знать
Матрицу модели обычно собирают как Перенос × Поворот × Масштаб. Перепутаете порядок — и объект окажется не там или искажённым. Матричное умножение некоммутативно: A×B≠B×A. Это самый частый источник «объект телепортировался».
Порядок имеет значение
Сравним два сценария над точкой (1,0): «сначала повернуть, потом сдвинуть» и «сначала сдвинуть, потом повернуть». Результаты разные.
import math
def rotate(x, y, deg):
a = math.radians(deg)
return (x*math.cos(a) - y*math.sin(a), x*math.sin(a) + y*math.cos(a))
def translate(x, y, dx, dy):
return (x + dx, y + dy)
x, y = 1.0, 0.0
# Вариант A: повернуть на 90, затем сдвинуть на (2,0)
rx, ry = rotate(x, y, 90)
ax, ay = translate(rx, ry, 2, 0)
# Вариант B: сдвинуть на (2,0), затем повернуть на 90
tx, ty = translate(x, y, 2, 0)
bx, by = rotate(tx, ty, 90)
print("A (поворот->перенос):", (round(ax,2), round(ay,2)))
print("B (перенос->поворот):", (round(bx,2), round(by,2)))
Вывод:
A (поворот->перенос): (2.0, 1.0) B (перенос->поворот): (0.0, 3.0)
Те же два действия, разный порядок — точки оказались в совершенно разных местах.
Канонический порядок: масштаб → поворот → перенос
Обычно объект сначала масштабируют (вокруг своего центра), затем поворачивают, затем переносят в мир. На уровне записи матриц это M = T * R * S, потому что матрицы применяются к вектору справа налево: сперва S, потом R, потом T.
Запись: M = T * R * S
Действие на вектор v: M*v = T*(R*(S*v))
масштаб ->|
поворот ->|
перенос ->|
Зачем сворачивать в одну матрицу
Если каждый кадр умножать вершину последовательно на S, R, T — это три умножения на вершину. Гораздо дешевле один раз перемножить T×R×S в матрицу M на процессоре и слать в шейдер готовую M: тогда на вершину остаётся одно умножение.
Как работает под капотом
CPU собирает матрицу модели для каждого объекта, перемножает с View и Projection в MVP и передаёт её в вершинный шейдер как uniform. Шейдер делает единственное умножение MVP * vec4(pos, 1.0). Так миллионы вершин обрабатываются с минимумом работы на каждую.
Частые ошибки
- Переставить местами поворот и перенос и удивляться, что объект вращается вокруг чужой точки.
- Считать умножение матриц коммутативным — оно не коммутативно.
- Применять неравномерный масштаб после поворота, искажая объект непредсказуемо.
Итоги
- Умножение матриц некоммутативно: порядок меняет результат.
- Канон: масштаб → поворот → перенос, в записи M = T*R*S.
- Матрицы применяются к вектору справа налево.
- Свёртка в одну матрицу экономит умножения на каждой вершине.