Урок
2: Использование матриц преобразований
Что такое матрицы преобразований и зачем они нужны ? Перед тем как разобраться с этим понятием, вспомним немного математику.
Пусть у нас имеется некая вершина v1, которую мы хотим переместить в вершину v2, вращая ее против часовой стрелки на угол A.
Рисунок 1. Поворот вершины против часовой стрелки
Воспользовавшись простыми формулами, находим координаты точки v2:
x2
= x1*cos(A)
y2 = y1*sin(A) , где x1 и y1 - координаты точки v1
Зная правило умножения вектора на матрицу, мы можем записать наши формулы в более элегантном виде:
|
x | | a11 a12 | = | x' |
| y | | a21 a22 | | y' |
, где x' = x*a11 + y*a21
y' = x*a12 + y*a22
подставив a11 = cos(A), a12 = 0, a21 = 0, a22 = sin(A), получим:
|
x2 | = | x1 | | cos(A) 0 |
| y2 | | y1 | | 0 sin(A) |
, где x2 = x1*cos(A)
y2 = y1*sin(A)
тем самым, мы получили некую матрицу M, которая и является матрицей преобразования, предназначенная для вращения любой вершины на произвольный угол.
M
= | cos(A) 0 |
| 0 sin(A) |
Когда вы работаете с 3-D графикой, вы можете преобразовывать любую вершину в другую, используя уже 4-х мерную матрицу.
Основные матричные преобразования - это перемещение, вращение и масштабирование. Следующая матрица перемещает вершину (x,y,z) в вершину (x',y',z') на расстояние Tx, Ty, Tz:
Для вращение вершины (x,y,z) вокруг произвольной координатной оси, используются следующие матрицы:
,вращение
вокруг оси X
,вращение
вокруг оси Y
,вращение
вокруг оси Z
Для масштабирования вершины (x,y,z) на коэффициенты Sx,Sy,Sz, применяется следующая матрица:
Несмотря на кажущийся громоздкость применения матриц, у них есть одно неоспоримое преимущество. Чтобы получить несколько преобразований сразу, не нужно каждый раз умножать вершину на новую матрицу, достаточно лишь предварительно перемножить все матрицы и получить одну результирующею матрицу:
W = M1*M2*M3
,где например M1 - матрица поворота вокруг оси X, M2 - матрица перемещения, M3 - матрица масштабирования. Тогда умножая любую вершину на матрицу W, мы получим три преобразования сразу.
Понятие матриц неразрывно связано с понятием геометрического конвейера Direct3D. Он состоит из трех матриц преобразования:
Рисунок 2. Геометрический конвейер Direct3D
Входными данными геометрического конвейера являются вершины, точнее их координаты ( Vertices - вершины ). Они последовательно преобразуются через три матрицы: World - мировую, View - видовую, Projection - проекционную. Потом все точки проходят отсечение - clipping ( т.е. отсекаются все точки, которые не будут видны на экране ), масштабируются и приводятся к экранным координатам - viewport scalling.
Рассмотрим все три преобразования:
1. Мировое преобразование меняет локальные координаты модели, в мировые координаты.
2. Видовое преобразование, отражая расположение наблюдателя в мировом пространстве, преобразует точки в пространство камеры.
3. Проективное преобразование переносит координаты точек из пирамиды просмотра (viewing frustum) в кубоид, который потом и будет отражаться на экране.
Теперь плавно перейдем от теоретической части к практической. Возьмем за основу пример из первого нашего урока. Сперва напишем функцию, которая будет устанавливать матрицы преобразования геометрического конвейера Direct3D:
//
Функция SetMatrices() устанавливает матрицы преобразований
void SetMatrices(void)
{
D3DXMATRIX matWorld;
D3DXMATRIX matView;
D3DXMATRIX matProj;
// Установка мировой матрицы
D3DXMatrixRotationY(&matWorld,timeGetTime()/500.0f);
d3d_device->SetTransform(D3DTS_WORLD,&matWorld);
// Установка видовой матрицы
D3DXMatrixLookAtLH(&matView,&D3DXVECTOR3(0.0f,0.0f,-3.5f),
&D3DXVECTOR3(0.0f,0.0f,0.0f),
&D3DXVECTOR3(0.0f,1.0f,0.0f));
d3d_device->SetTransform(D3DTS_VIEW,&matView);
// Установка проектной матрицы
D3DXMatrixPerspectiveFovLH(&matProj,D3DX_PI/4,1.0f,1.0f,100.0f);
d3d_device->SetTransform(D3DTS_PROJECTION,&matProj);
}
Немного изменим функцию прорисовки сцены, добавив в нее вызов предыдущей функции:
//
Функция RenderDirect3D() прорисовывает сцену
void RenderDirect3D(void)
{
//
Очищение заднего буфера
d3d_device->Clear(0,NULL,D3DCLEAR_TARGET,D3DCOLOR_XRGB(0,0,0),1.0f,0);
//
Начало прорисовки сцены
d3d_device->BeginScene();
//
Установка матриц преобразований
SetMatrices();
//
Прорисовка сцены
d3d_device->SetStreamSource(0,d3d_vb,sizeof(CUSTOMVERTEX));
d3d_device->SetVertexShader(D3DFVF_CUSTOMVERTEX);
d3d_device->DrawPrimitive(D3DPT_TRIANGLELIST,0,3);
//
Конец прорисовки сцены
d3d_device->EndScene();
d3d_device->Present(NULL,NULL,NULL,NULL);
}
Вот и все, мы получим два вращающихся объекта, которые раньше у нас были просто плоскими. Полный исходный текст программы и exe-файл можно взять здесь.