Линейная алгебра · модуль 4 из 14
Матрица 4×4: как 3D-движок двигает модель
Каждая вершина записывается в однородных координатах (x, y, z, 1) и умножается на матрицу 4×4. Блок 3×3 слева сверху поворачивает и масштабирует, четвёртый столбец сдвигает, нижняя строка отвечает за перспективу.
- e₁′ (столбец 1)
- e₂′ (столбец 2)
- e₃′ (столбец 3)
- исходная модель
Потяните поле мышью или пальцем, чтобы повернуть камеру.
Теория
Точка трёхмерного пространства $(x, y, z)$ записывается в однородных координатах как $(x, y, z, 1)$. Тогда любое аффинное преобразование — поворот, масштаб, скос и сдвиг — выражается умножением на матрицу $4 \times 4$:
$$ \begin{pmatrix} x' \\ y' \\ z' \\ w \end{pmatrix} = \begin{pmatrix} m_{11} & m_{12} & m_{13} & t_x \\ m_{21} & m_{22} & m_{23} & t_y \\ m_{31} & m_{32} & m_{33} & t_z \\ p_1 & p_2 & p_3 & m_{44} \end{pmatrix} \begin{pmatrix} x \\ y \\ z \\ 1 \end{pmatrix}. $$
- Блок $3 \times 3$ слева сверху задаёт линейную часть: поворот, масштаб, скос, отражение. Его столбцы — образы базисных векторов $e_1, e_2, e_3$.
- Четвёртый столбец $(t_x, t_y, t_z)$ задаёт сдвиг. Без четвёртой координаты сдвиг нельзя записать умножением на матрицу.
- Нижняя строка отвечает за перспективу: если она отлична от $(0, 0, 0, 1)$, координаты делятся на $w$.
Определитель блока $3 \times 3$ показывает, во сколько раз меняется объём. При $\det = 0$ модель схлопывается в плоскость или линию, при $\det < 0$ меняется ориентация (модель зеркалится).
Композиция. Последовательные преобразования перемножаются: сначала $R$, затем $T$ даёт матрицу $T \cdot R$. Умножение матриц некоммутативно, поэтому $T R \ne R T$ в общем случае.
Где это применяется в IT
Так работают все 3D-движки: Unity, Unreal, OpenGL, WebGL. Матрицы модели, камеры и проекции перемножаются в одну матрицу $4 \times 4$ (MVP), и видеокарта умножает на неё миллионы вершин в каждом кадре.
- Однородные координаты. Координата $w = 1$ позволяет записать сдвиг как умножение на матрицу; с матрицей $3 \times 3$ так сделать нельзя.
- Порядок важен. $T \cdot R$ (повернуть, затем сдвинуть) не равно $R \cdot T$. Включите накопление преобразований и проверьте.
- Нормали. При $\det < 0$ модель зеркалится, у неё выворачиваются нормали, и движку приходится менять порядок обхода треугольников.
Код на Python
Загружаю пример…