ИнтВиз

Линейная алгебра · модуль 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

Загружаю пример…