Матричные преобразования
A lot of calculations in UNIGINE are performed by using matrices. Actually, matrix transformations are one of the main concepts of 3D engines. This article contains an explanation of matrix transformations with usage examples. Многие вычисления в UNIGINE выполняются с использованием матриц. Собственно, матричные преобразования - одна из основных концепций 3D-движков. Эта статья содержит объяснение матричных преобразований с примерами использования.
See AlsoСмотрите также#
- An article about mat4 and dmat4 UNIGINE data types. Статья о типах данных UNIGINE mat4 и dmat4 .
- The description of Math Matrix Functions. Описание матричных математических функций .
TransformationsТрансформации#
In simple terms, a matrix in 3D graphics is an array of numbers arranged in rows and columns: Проще говоря, матрица в трехмерной графике - это массив чисел, упорядоченных по строкам и столбцам:
Usually, 4x4 matrices are used. Such size (4x4) of matrices is caused by the translation state in 3D space. When you put a new node into the world, it has a 4x4 world transform matrix that defines the position of the node in the world. Обычно используются матрицы 4x4 . Такой размер матриц (4х4) обусловлен состоянием трансляции в трехмерном пространстве. Когда вы помещаете новый узел в мир, он имеет мировую матрицу трансформации мира 4x4, которая определяет его положение в мире.
In UNIGINE, matrices are column major (column-oriented). Hence, the first column of the transform matrix represents the X vector of the local coordinate system (v1), the second represents the Y vector (v2), the third represents the Z vector (v3), and the fourth represent the translation vector t. First three columns show directions of local coordinate axes (rotation) and the scale of the origin. The last column contains the translation of the local origin relatively to the world origin. В UNIGINE матрицы являются основными по столбцам (ориентированными по столбцам). Следовательно, первый столбец матрицы преобразования представляет вектор X локальной системы координат ( v1 ), второй представляет вектор Y ( v2 ), третий представляет вектор Z ( v3 ), а четвертый представляет вектор перемещения t . Первые три столбца показывают направления локальных осей координат ( поворот ) и масштаб начала координат. Последний столбец содержит перемещение локального начала координат относительно мирового.
Identity MatrixЕдиничная матрица#
The world origin has the following matrix: Начало координат имеет следующую матрицу:
This matrix is called identity matrix, a matrix with ones on the main diagonal, and zeros elsewhere. If a matrix is multiplied by the identity matrix, that won't change anything: the resulting matrix will be the same as it was before multiplying. Эта матрица называется единичной матрицей , матрицей с единицами на главной диагонали и нулями в другом месте. Если матрица умножается на единичную матрицу, это ничего не изменит: результирующая матрица будет такой же, как и до умножения.
If the local origin has the identity matrix, it means the local origin and the world origin are coincident. Если локальное начало координат имеет единичную матрицу, это означает, что местное начало координат и мировое начало координат совпадают .
RotationВращение#
To change the orientation of the local origin, the first three columns of the matrix should be changed. Чтобы изменить ориентацию локального начала координат, следует изменить первые три столбца матрицы.
To rotate the origin along different axes, you should use proper matrices: Чтобы повернуть начало координат по разным осям, вы должны использовать соответствующие матрицы:
In the matrices given above, α is a rotation angle along the axis. В приведенных выше матрицах α - это угол поворота вдоль оси.
The next matrix shows the rotation of the local origin along the Y axis at 45 degrees: Следующая матрица показывает поворот локального начала координат по оси Y на 45 градусов:
TranslationПеремещение#
The last column of the transform matrix shows the position of the local origin in the world relatively to the world origin. The next matrix shows the translation of the origin. The translation vector t is (3, 0, 2). Последний столбец матрицы преобразования показывает положение локального начала координат в мире относительно начала координат. Следующая матрица показывает перемещение начала координат. Вектор перемещения t равен (3, 0, 2) .
ScalingМасштабирование#
The length of the vector shows the scale coefficient along the axis. Длина вектора показывает масштабный коэффициент по оси.
To calculate the vector length (also known as magnitude), you should find a square root of the sum of the squares of vector components. The formula is the following: Чтобы вычислить длину вектора (также известную как величина ), вы должны найти квадратный корень из суммы квадратов компонентов вектора. Формула следующая:
|vector length| = √(x² + y² + z²)
The following matrix scales the local origin up to 2 units along all axes. Следующая матрица масштабирует местное начало координат до 2 единиц по всем осям.
Cumulating TransformationsНакопление преобразований#
The order of matrix transformations in code is very important. Порядок преобразования матриц в коде очень важен.
If you want to implement a sequence of cumulating transformations, the transformations order in code should be as follows: Если вы хотите реализовать последовательность кумулирующих преобразований, порядок преобразований в коде должен быть следующим:
TransformedVector = TransformationMatrixN * ... * TransformationMatrix2 * TransformationMatrix1 * Vector
Transformations are applied one by one starting from TransformationMatrix1 and ending with TransformationMatrixN. Преобразования применяются одно за другим, начиная с TransformationMatrix1 и заканчивая TransformationMatrixN.
Exampleпример#
This example shows the difference between two orders of matrix transformations. Этот пример показывает разницу между двумя порядками преобразования матриц.
The code example below gets the material ball object. In the first case, rotation is followed by translation and in the second case, translation is followed by rotation. В приведенном ниже примере кода получается объект material ball. В первом случае за вращением следует перемещение, а во втором случае за перемещением следует поворот.
In the AppWorldLogic.cs file, do the following: В файле AppWorldLogic.cs выполните следующие действия:
- Define the Node instance for the material ball. Определите экземпляр Node для material ball.
- Enable the visualizer by passing show_visualizer 1 command to the run() function of the Console class. Включите визуализатор, передав команду show_visualizer 1 функции run() класса Console.
- Get the material ball from the Editor. Получите material ball из редактора.
- Create new rotation and translation matrices. Создайте новые матрицы поворота и перемещения.
- Calculate the new transformation matrix and apply it to the material ball. Вычислите новую матрицу преобразования и примените ее к material ball.
- Render the world origin by using renderVector() method of the Visualizer class. Визуализируйте происхождение мира с помощью метода renderVector() класса Visualizer.
// AppWorldLogic.cs file
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Unigine;
namespace UnigineApp
{
class AppWorldLogic : WorldLogic
{
Node material_ball;
/* ... */
public override bool Init()
{
// enable the visualizer for world origin rendering
Console.Run("show_visualizer 1");
// get the material ball
material_ball = World.GetNodeByName("material_ball");
// create rotation and translation matrices
dmat4 rotation_matrix = new dmat4(MathLib.RotateZ(-90.0f));
dmat4 translation_matrix = new dmat4(MathLib.Translate(new vec3(0.0f, 3.0f, 0.0f)));
// create a new transformation matrix for the material ball
// by multiplying the current matrix by rotation and translation matrices
dmat4 transform = translation_matrix * rotation_matrix * material_ball.Transform;
// set the transformation matrix to the material ball
material_ball.Transform = transform;
return true;
}
public override bool Update()
{
// render world origin
Visualizer.RenderVector(new dvec3(0.0f,0.0f,0.1f), new dvec3(1.0f,0.0f,0.1f), new vec4.RED);
Visualizer.RenderVector(new dvec3(0.0f,0.0f,0.1f), new dvec3(0.0f,1.0f,0.1f), new vec4.GREEN);
Visualizer.RenderVector(new dvec3(0.0f,0.0f,0.1f), new dvec3(0.0f,0.0f,1.1f), new vec4.BLUE);
return true;
}
/* ... */
}
}
To change the order, just change the line of cumulating transformations: Чтобы изменить порядок, достаточно изменить строку накопления преобразований:
dmat4 transform = rotation_matrix * translation_matrix * material_ball.Transform;
The result would be different. The pictures below show the difference (camera is located at the same place). Результат был бы другим. На фотографиях ниже показана разница (камера расположена в том же месте).
Order: rotation and translation Порядок: вращение и перемещение
|
Order: translation and rotation Порядок: перемещение и вращение
|
The pictures above show the position of the meshes related to the world origin. На изображениях выше показано положение сеток относительно начала мира.
Matrix HierarchyМатричная иерархия#
One more important concept is the matrix hierarchy. When a node is added into the world as a child of another node, it has a transformation matrix that is related to the parent node. That is why the Node class distinguishes between the functions getTransform(), setTransform() and getWorldTransform(), setWorldTransform(), which return the local and the world transformation matrices respectively. Еще одно важное понятие - матричная иерархия. Когда узел добавляется в мир как дочерний по отношению к другому узлу, он имеет матрицу преобразования, связанную с родительским узлом. Вот почему класс Node различает функции getTransform(), setTransform() и getWorldTransform(), setWorldTransform(), которые возвращают локальную и мировую матрицы преобразования соответственно.
What is the reason of using a matrix hierarchy? To move a node relative to another node. And when you move a parent node, child nodes will also be moved. В чем причина использования матричной иерархии? Чтобы переместить узел относительно другого узла. И когда вы перемещаете родительский узел, дочерние узлы также будут перемещены.
Parent origin is the same with the world origin Родительское происхождение совпадает с мировым происхождением
|
Parent origin has been moved and the child origin has also been moved Родительский источник был перемещен, и дочерний источник также был перемещен
|
Pictures above show the main point of the matrix hierarchy. When the parent origin (node) is moved, the child origin will also be moved and the local transformation matrix of the child would not be changed. But the world transformation matrix of the child will be changed. If you need the world transformation matrix of the child related to the world origin, you should use the getWorldTransform(), setWorldTransform() functions; in case, when you need the local transformation matrix of the child related to the parent, you should use the getTransform(), setTransform() functions. Рисунки выше показывают суть матричной иерархии. Когда начало координат родителя (ноды) перемещается, начало координат дочерней ноды также будет перемещено, и локальная матрица преобразования дочернего элемента не будет изменена. Но матрица трансформации мира дочерней ноды будет изменена. Если вам нужна матрица преобразования мира дочернего элемента, связанная с началом координат мира, вы должны использовать функции getWorldTransform(), setWorldTransform(); в случае, когда вам нужна локальная матрица преобразования дочернего элемента, связанного с родительским, вы должны использовать функции getTransform(), setTransform().
Exampleпример#
The following example shows how important the matrix hierarchy is. Следующий пример показывает, насколько важна иерархия матриц.
In this example, we get the node from and clone it. Then we change transformation matrices of these nodes. We review two cases: В этом примере мы получаем узел и клонируем его. Затем мы меняем матрицы преобразования этих узлов. Рассмотрим два случая:
- The two nodes are independent. Два узла независимы.
- One node is the child of the other. Один узел является дочерним для другого.
In the AppWorldLogic.cs, implement the following code: В AppWorldLogic.cs реализуйте следующий код:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Unigine;
namespace UnigineApp
{
class AppWorldLogic : WorldLogic
{
Node material_ball_child;
Node material_ball_parent;
/* ... */
public override bool Init()
{
// enable the visualizer for world origin rendering
Console.Run("show_visualizer 1");
// get the material ball and clone it
material_ball_child = World.GetNodeByName("material_ball");
material_ball_parent = material_ball_child.Clone();
// make the one node the child of another
material_ball_parent.AddChild(material_ball_child);
// create rotation and translation matrices for the first material_ball
dmat4 rotation_matrix = new dmat4(MathLib.RotateZ(-90.0f));
dmat4 translation_matrix = new dmat4(MathLib.Translate(new vec3(0.0f, 3.0f, 0.0f)));
// create translation matrix for the second (parent) material ball
dmat4 translation_matrix_parent = new dmat4(MathLib.Translate(new vec3(0.5f, 0.0f, 1.0f)));
// create a new transformation matrix for the material ball
// by multiplying the current matrix by rotation and translation matrices
dmat4 transform = rotation_matrix * translation_matrix * material_ball_child.Transform;
dmat4 transform_parent = translation_matrix_parent * material_ball_parent.Transform;
// set the transformation matrix to the material ball
material_ball_child.Transform = transform;
material_ball_parent.Transform = transform_parent;
return true;
}
public override bool Update()
{
// render world origin
Visualizer.RenderVector(new dvec3(0.0f,0.0f,0.1f), new dvec3(1.0f,0.0f,0.1f), new vec4.RED);
Visualizer.RenderVector(new dvec3(0.0f,0.0f,0.1f), new dvec3(0.0f,1.0f,0.1f), new vec4.GREEN);
Visualizer.RenderVector(new dvec3(0.0f,0.0f,0.1f), new dvec3(0.0f,0.0f,1.1f), new vec4.BLUE);
return true;
}
/* ... */
}
}
If you comment the following line: Если закомментировать следующую строку:
// make the one node the child of another
material_ball_parent.AddChild(material_ball_child);
you get a different result: вы получите другой результат:
Parent-child nodes Родительско-дочерние узлы
|
Nodes are independent Узлы независимы
|
When nodes are independent, they have different local and world transformation matrices. In case of parent-child nodes, the child's local transformation matrix remains the same after moving, but the world transformation matrix will be changed (you can check it by using the debug profiler). Когда узлы независимы, они имеют разные локальные и мировые матрицы преобразования. В случае узлов «родитель-потомок» локальная матрица преобразования дочернего элемента остается такой же после перемещения, но матрица преобразования мира будет изменена (вы можете проверить ее с помощью профилировщика отладки).