Загрузка...
 
Печать

Библиотека D3DX (DirectX 8)

Несмотря на то, что Microsoft упростила многие интерфейсы, пользоваться ими не так-то просто.1 Для того, чтобы упростить жизнь программерам и ускорить работу с графикой софтверный гигант создал библиотеку D3DX. Она содержит в себе множество полезных функций для работы с графикой (мешами, текстурами, шрифтами, математическими вычислениями и т.д.).
Для начала работы с D3DX необходимо добавить в Решение/Проект библиотеку D3DX8.LIB из подкаталога lib установленного DirectX SDK 8 (путь по умолчанию C:\DXSDK\lib\) + добавить в топовый заголовочный файл директиву #include D3DX8.H.
Напомню, DirectX SDK 8 можно взять здесь: http://old-dos.ru/index.php?page=files&mode=files&do=show&id=2629(external link)
Имена всех функций данной библиотеки начинаются с префикса D3DX. Помимо функций, она также содержит COM-объекты, как например ID3DXBaseMesh.

Математические вычисления с помощью библиотеки D3DX

3D-графика включает в себя интенсивные математические вычисления. Много лет назад 3D-графика была скорее мечтой, чем реальностью. Компьютеры того времени просто не могли производить вычисления достаточно быстро. Сегодня дела в этом плане обстоят заметно лучше и нам доступна 3D-графика с кучей крутых эффектов. Математические вычисления выполняются при расчёте положения объектов в 3D-пространстве.

Математические матрицы (Math matrices)

Матричная математика (Matrix math) является разделом линейной алгебры (linear algebra). Она позволяет заметно упростить вычисления, а также снизить их объём. Причём не только в 3D-графике. Нам она нужна в первую очередь для расчёта 3D-трансформаций.
В свете того, что любой объект в Direct3D состоит из множества вершин (vertices), именно Direct3D занимается преобразованием (трансформацией) их координат с целью последующего вывода на экран. В каждом кадре ты можешь трансформировать тысячи вершин, из которых состоит сцена. Для таких преобразований Direct3D использует математические матрицы(external link), представляющие собой таблицы чисел, в которых каждый элемент имеет своё особое значение. В нашем случае эти элементы (=числа) представляют собой трансформации, применяемые к вершинам. Скомпоновав все необходимые вычисления в одну компактную форму (матрицу), мы здорово экономим время и ресурсы.

Закрыть
noteОбрати внимание

Матричная математика применима только к 3D-координатам. При работе с уже трансформированными координатами (например координатами экранного пространства) дальнейшие преобразования не требуются.

Построение матриц (Matrix construction). Класс D3DXMATRIX библиотеки D3DX.

Матрицы бывают самых разных размеров. Но в нашем случае нас интересуют только матрицы размером 4х4 элемента, состоящие из 4-х строк (rows) и 4-х столбцов (columns).
Direct3D хранит матрицы в специальной структуре D3DMATRIX:

Структура D3DMATRIX
typedef struct _D3DMATRIX {
 D3DVALUE _11, _12, _13, _14;
 D3DVALUE _21, _22, _23, _24;
 D3DVALUE _31, _32, _33, _34;
 D3DVALUE _41, _42, _43, _44;
} D3DMATRIX;

Закрыть
noteОбрати внимание

Тип данных D3DVALUE представляет собой макрос, основанный на типе float.


Для заполнения матрицы данными трансформации (transformation data) обычно применяют библиотеку D3DX. (Но это далеко не единственный способ.) В D3DX вместо структуры D3DMATRIX используется производный объект специального класса D3DXMATRIX, оснащённого массой полезных функций.
Такие преобразования (трансформации) координат как трансляция (translation) и изменение масштаба (scale) используют по одной матрице матрицу. Но для выполнения вращения (rotation) задействуются целых 3 матрицы (по одной на каждую ось вращения). Это значит, что для выполнения типичного полного цикла трансформаций (вращение, трансляция, изменение масштаба) в общей сложности потребуется 5 матриц.
Первый набор функций для создания матриц вращения выглядит так:

D3DXMATRIX *D3DXMatrixRotationX (
 D3DXMATRIX *pOut,  // Матрица на выходе (output matrix)
 FLOAT Angle);     // Угол поворота по оси X вокруг центра

D3DXMATRIX *D3DXMatrixRotationY (
 D3DXMATRIX *pOut,  // Матрица на выходе (output matrix)
 FLOAT Angle);     // Угол поворота по оси Y вокруг центра

D3DXMATRIX *D3DXMatrixRotationZ (
 D3DXMATRIX *pOut,  // Матрица на выходе (output matrix)
 FLOAT Angle);     // Угол поворота по оси Z вокруг центра


Передав в каждую из этих функций указатель на исходную матрицу а также значение угла поворота (в радианах), получим на выходе преобразованную матрицу.

Закрыть
noteОбрати внимание

Все функции библиотеки D3DX для работы с матрицами возвращают указатель типа D3DXMATRIX, представляющий собой указатель на результирующую матрицу. Это позволяет использовать данные функции в качестве встроенных (inline) в другие функции. Вот пример:
D3DXMATRIX matMatrix, matResult;
matResult = D3DXMatrixRotationZ(&matMatrix, 1.57f);


Следующая функция создаёт матрицу трансляции (translation matrix), которая используется для перемещения (изменения текущей позиции) объектов:

Прототип функции D3DXMatrixTranslation
D3DXMATRIX *D3DXMatrixTranslation(
 D3DXMATRIX *pOut,  // Матрица на выходе (output matrix)
 FLOAT x,   // Смещение координаты по оси X
 FLOAT y,   // Смещение координаты по оси Y
 FLOAT z);  // Смещение координаты по оси Z

Здесь координаты представляют собой смещения (offsets) координат относительно локального центра координат (origin) объекта. Данные транслируемые значения используются для преобразования вершин объекта из локальных координат пространства (local space coordinates) в мировую систему координат (world space coordinates).

Функция D3DXMatrixScaling изменяет масштаб (scale) объектов относительно их локального центра координат:

Прототип функции D3DXMatrixScaling
D3DXMATRIX *D3DXMatrixScaling(
 D3DXMATRIX *pOut,  // Матрица выода (output matrix)
 FLOAT sx,  // Изменение масштаба по оси x.
 FLOAT sy,  // Изменение масштаба по оси y.
 FLOAT sz);  // Изменение масштаба по оси z.

Обычный (исходный) масштаб объекта принят за 1,0. Для увеличения объекта в 2 раза указывают значение 2,0 для координат по каждой из осей. Для уменьшения объекта в 2 раза указывают масштаб 0,5.

Помимо рассмотренных выше матриц, в Direct3D (и высшей математике) также существует специальный вид матриц - единичная матрица (identity matrix). Несколько её элементов установлены в 0, остальные - в 1. При перемножении единичной матрицы на обычную в результате получают исходную обычную (неизменённую) матрицу. Единичные матрицы полезны когда надо скомбинировать (=перемножить) две матрицы, но при этом исходная матрица должна остаться без изменений. Для создания единичной матрицы в D3DX даже есть отдельная функция D3DXMatrixIdentity:

D3DXMATRIX *D3DXMatrixIdentity(D3DXMATRIX *pOut);

В качестве парамтера передаётся результирующая матрица (output matrix).

Вот пример применения всех расмотренных выше матриц:

...
D3DXMATRIX matXRot, matYRot, matZRot;
D3DXMATRIX matTrans, matScale;

// Настраиваем поворот объекта на 45 град. (0,785 радиан) по каждой из осей.
D3DXMatrixRotationX(&matXRot, 0.785f);
D3DXMatrixRotationY(&matYRot, 0.785f);
D3DXMatrixRotationZ(&matZRot, 0.785f);

// Настраиваем транслацию (перемещение) объекта по вектору (100,200,300).
D3DXMatrixTranslation(&matTrans, 100.0f, 200.0f, 300.0f);

// Изменяем масштаб (scale) объекта, увеличивая его в 2 раза по каждой из осей.
D3DXMatrixScaling(&matScale, 2.0f, 2.0f, 2.0f);
...

Комбинирование матриц (Combining matrices)

После заполнения различных матриц значениями, используемыми при трансформациях, можно применять их к каждой отдельной вершине. Для упрощения задачи отдельные матрицы, содержащие значения для трансляции, поворота и изменения масштаба, можно комбинировать в одну путём их простого перемножения. Данную операцию также назвают конкатенацией матриц(external link) (matrix concatenation) и она является ключом к оптимизации всех матричных вычислений.
Создав одну матрицу в каждом кадре ты можешь применять её к каждой вершине сцены. В этом случае эффект будет такой же, как и при применнении каждой из составляющих матриц по отдельности.
Матрицы не так сложны в использовании. Просто в них надо немного разобраться.
В D3DX для комбинирования двух матриц есть специальная функция D3DXMatrixMultiply:

Прототип функции D3DXMatrixMultiply
D3DXMATRIX *D3DXMatrixMultiply(
 D3DXMATRIX *pOut,  // Результирующая матрица (output matrix)
 CONST D3DXMATRIX *pM1,   // Матрица-операнд 1 (source matrix 1).
 CONST D3DXMATRIX *pM2);  // Матрица-операнд 2 (source matrix 2).

Указав две комбинируемые матрицы и матрицу результат на выходе получим готовую матрицу, результат сложения двух исходных матриц.
Вооружившись данной функцией, скомбинируем матрицы вращения (3 шт.; по одной на каждую ось), трансляции (translation) и масштабирования (scale) в одну результирующую матрицу, которая включает в себя все эти трансформации:

D3DMATRIX matResult;  // Результирующая (output) матрица.

// Приводим результирующую матрицу к виду единичной матрицы (identity matrix).
D3DXMatrixIdentity(&matResult);

// Перемножаем (комбинируем) результирующую матрицу с матрицей масштабирования.
D3DXMatrixMultiply(&matResult, &matResult, &matScale);

// Перемножаем (комбинируем) результирующую матрицу с матрицами вращения.
D3DXMatrixMultiply(&matResult, &matResult, &matXRot);
D3DXMatrixMultiply(&matResult, &matResult, &matYRot);
D3DXMatrixMultiply(&matResult, &matResult, &matZRot);

// Перемножаем (комбинируем) результирующую матрицу с матрицей трансляции.
D3DXMatrixMultiply(&matResult, &matResult, &matTrans);

Закрыть
noteОбрати внимание

Порядок перемножения матриц очень важен. В данном примере результирующая матрица сначала была скомбинирована с матрицей масштабирования, затем с матрицами вращения (по осям X, Y и Z), и в последнюю очередь с матрицей трансляции. Возьми эту последовательность за правило. Если комбинировать матрицы в другом порядке, то и результирующая матрица будет другой, что в будущем приведёт к нежелательным последствиям.

Алгоритм преобразования координат. Local -> World -> View -> Projection

Координаты каждой вершины, прежде чем та будет отрендерена на экран монитора, проходят несколько стадий преобразований:

  1. Локальные (local, по сути они являются нетрансформированными - untransformed) координаты сперва преобразуются в мировые (world). Для этого применяют мировую матрицу трансформации (world transformation matrix, world matrix), содержащую преобразования, применяемые для позиционирования объекта в 3D-пространстве. Иногда её называют local-to-world-матрицей.
  2. Мировые (world) координаты преобразуются в координаты вида (view coordinates). Для этого применяют матрицу вида (viewing matrix), которая позиционирует вершины относительно наблюдателя (=виртуальной камеры) в 3D-пространстве. Иногда её называют world-to-view-матрицей.
  3. Координаты вида (view coordinates) преобразуются в координаты проекции (projection coordinates). Для этого применяется матрица проекции (projection matrix), которая проецирует 3D-координаты вершин на 2D-поверхность экрана монитора (в терминологии Windows GDI это холст (canvas), в Direct3D - это фрейм (frame)) для последующего рендеринга. Иногда её называют view-to-projection-матрицей.

Т.е. всего применяется 3 матрицы преобразований:

  • Мировая матрица (World matrix)
  • Матрица вида (View matrix)
  • Матрица проекции (Projection matrix)

Запомни порядок преобразования координат (в Direct3D он всегда неизменен):
Локальные -> Мировые -> Вида -> Проекции

Закрыть
noteОбрати внимание

При работе с матрицей вида (view matrix) небходимо использовать отрицательные (reverse, negative) значения положения вьюера (=виртуальной камеры) для его ориентирования на объекты. А всё из-за того, что как правило начальная позиция наблюдателя остаётся неизменной (locked) и находится в точке начала координат (0, 0, 0). Когда наблюдатель ("viewer") двигается относительно мира, то все объекты мира смещаются относительно него. Например, когда наблюдатель перемещается на 10 единиц (units) вперёд, то по факту объекты мира перемещаются на 10 единиц назад. Когда наблюдатель поворачивает "голову" на 10 градусов влево, то объекты мира, в свою очередь, тоже смещаются (вообще они вращаются относительно наблюдателя) на 10 градусов вправо.

Мировая матрица (world matrix) и матрица вида (view matrix), в свою очередь, представляет собой результирующую матрицу, полученную в результате перемножения матриц масштабирования, вращения (3 шт) и трансляции, рассмотренных выше. Так вот, для получения корректных матриц мира и вида их "компоненты" необходимо перемножать в строго определённом порядке:

  • При создании мировой матрицы (для пребразования локальных координат в мировые) порядок перемножения отдельных (individual) матриц следующий:

R = S*X*Y*Z*T
, где R - результирующая матрица; S - матрица масштабирования (scale matrix); X, Y и Z - матрицы вращения (по одной на каждую ось); T - матрица трансляции (translation matrix).

  • В создании матрицы вида (для преобразования мировых координат в координаты вида) участвуют только матрицы трансляции (translation) и вращения (rotation)! Здесь порядок перемножения отдельных (individual) матриц следующий:

R = T*X*Y*Z
, где R - результирующая матрица; T - матрица трансляции (translation matrix); X, Y и Z - матрицы вращения (по одной на каждую ось).

Источники:


1. Adams J. Programming Role Playing Games with DirectX 8.0. - Premier Press. 2002

Contributors to this page: slymentat .
Последнее изменение страницы Четверг 03 / Декабрь, 2020 00:38:19 MSK автор slymentat.

Помочь проекту

yoomoney.ru (бывший Яндекс-деньги): 410011791055108