netlib.narod.ru | < Назад | Оглавление | Далее > |
В этом разделе мы сосредоточимся на математике матриц. Их использование в трехмерной компьютерной графике будет рассмотрено в следующем разделе.
Матрицей m × n называется прямоугольный массив чисел, состоящий из m строк и n столбцов. Количество строк и столбцов определяет размер матрицы. Отдельный элемент матрицы идентифицируется путем указания его строки и столбца в состоящем из двух элементов спсике индексов; первый индекс определяет строку, а второй — столбец. Ниже в качестве примера приведены матрицы M размером 3 × 3, В размером 2 × 4 и С размером 3 × 2:
В большинстве случаев для обозначения матриц мы будем использовать заглавные полужирные буквы. Иногда матрицы состоят из единственной строки или единственного столбца. Чтобы отличать такие матрицы, мы дадим им специальные имена: вектор-строка (row vector) и вектор-столбец (column vector). Вот примеры таких векторов:
Для элементов вектора-строки и вектора-столбца необходим только один индекс. Иногда для идентификации элемента строки или столбца в качестве индекса мы будем использовать буквы.
Для пояснения рассматриваемых терминов в данном разделе будут использованые следующие четыре матрицы:
Две матрицы считаются равными, если они имеют одинаковую размерность и их соответствующие элементы равны. Например, A = C, поскольку матрицы A и C имеют одинаковую размерность и их соответствующие элементы равны. Мы говорим, что A ≠ B и A ≠ D поскольку у этих матриц либо разная размерность, либо не равны соответствующие элементы.
Мы можем умножить матрицу на скаляр для чего нам необходимо умножить каждый элемент матрицы на данный скаляр. Например, умножив D на скаляр k получим:
Если k = 2, получим:
Можно сложить две матрицы, но только в том случае, если у них одинаковая размерность. Сумма вычисляется путем сложения соответствующих элементов матриц. Например:
Аналогично сложению можно выполнять вычитание двух матриц, имеющих одинаковую размерность. Вычитание матриц иллюстрирует следующий пример:
Умножение матриц это наиболее важная операция, которая постоянно используется в трехмерной компьютерной графике. Именно умножение матриц позволяет осуществлять преобразование векторов и комбинировать несколько преобразований в одно. Преобразования будут рассмотрены в следующем разделе.
Чтобы получить произведение матриц AB необходимо чтобы количество столбцов матрицы A было равно количеству строк матрицы B. Если условие выполняется, произведение матриц определено. Рассмотрим представленные ниже матрицы A и B, с размерностью 2 × 3 и 3 × 3 соответственно:
Как видите, произведение AB определено поскольку количество столбцов матрицы A равно количеству строк матрицы B. Обратите внимание, что произведение BA, получаемое в результате перестановки множителей, не определено, потому что количество столбцов матрицы B не равно количеству строк матрицы A. Это говорит о том, что в обшем случае операция умножения матриц не коммутативна (то есть AB ≠ BA). Мы говорим «в общем случае не коммутативна» по той причине, что существует ряд частных случаев в которых операция умножения матриц ведет себя как коммутативная.
После того, как мы узнали в каких случаях произведение матриц определено, можно дать определение операции умножения матриц: если A — это матрица m × n, а B — матрица n × p, то их произведением будет матрица C, размером m × p, в которой элемент cij находится как скалярное произведение i-го вектора-строки матрицы A и j-го вектора-столбца матрицы B:
В этой формуле ai обозначает i-ый вектор-строку в матрице A, а bj — j-ый вектор-столбец матрицы B.
Давайте для примера вычислим произведение:
Произведение определено, поскольку количество столбцов матрицы A равно количеству строк матрицы B. Кроме того, обратите внимание, что размер полученной в результате матрицы — 2 × 2. Согласно формуле (4) получаем:
В качестве упражнения проверьте, что в данном случае AB ≠ BA.
И еще один, более общий, пример:
Существует особая матрица, называемая единичной матрицей (identity matrix). Это квадратная матрица все элементы которой равны нулю, за исключением тех, что расположены на главной диагонали — эти элементы равны единице. Ниже приведены примеры единичных матриц размером 2 × 2, 3 × 3 и 4 × 4:
Единичная матрица действует как мультипликативное тождество:
Следовательно, операция умножения на единичную матрицу не изменяет исходную матрицу. Более того, умножение на единичную матрицу это один из случаев, когда операция умножения матриц является коммутативной. Вы можете думать о единичной матрице как о числе 1 для матриц.
ПРИМЕР | Проверьте, что в результате умножения матрицы М = на единичную матрицу размером 2 × 2 получается матрица М. |
|
В математике матриц нет аналога операции деления, но зато есть мультипликативная операция инвертирования. Приведенный ниже список обобщает важные особенности инвертирования:
Инвертировать можно только квадратные матрицы, так что когда мы говорим об инвертировании матрицы, подразумевается, что мы имеем дело с квадратной матрицей.
В результате инвертирования матрицы M размером n × n получается матрица размером n × n, которую мы будем обозначать M-1.
Не всякую квадратную матрицу можно инвертировать.
Если перемножить исходную и инвертированную матрицы, получится единичная матрица: MM-1 = M-1M = I. Обратите внимание, что в случае перемножения исходной и инвертированной матриц операция умножения матриц коммутативна.
Инверсия матриц применяется для нахождения искомой матрицы в уравнениях. Для примера возьмем выражение p' = pR и предположим, что нам известны p' и R, а требуется найти p. Сначала вычислим R-1 (подразумевается, что эта матрица существует). Получив R-1 можно вычислить p по следующему алгоритму:
Описание способа вычисления инвертированной матрицы выходит за рамки этой книги, но вы можете его найти в любом учебнике линейной алгебры. В разделе «Базовые преобразования» мы получим инверсию нескольких матриц, с которыми будем работать. В раздеде «Матрицы в библиотеке D3DX» мы познакомимся с функцией библиотеки D3DX, которая может инвертировать матрицу за нас.
Завершая раздел об инвертировании матриц представим вам одно полезное свойство, касающееся инвертирования произведения: (AB)-1 = B-1A-1. Здесь подразумеваеся, что матрицы A и B могут быть инвертированы и что обе они — квадратные матрицы одинакового размера.
Транспонирование матрицы осуществляется путем перестановки ее строк и столбцов. Следовательно, результатом транспонирования матрицы m × n будет матрица n × m. Результат транспонирования матрицы M мы будем обозначать MT.
ПРИМЕР | Транспонируйте следующие две матрицы: Напомним, что транспонирование матрицы осуществляется путем перестановки ее строк и столбцов. Следовательно: |
|
Программируя приложения Direct3D мы чаще всего будем использовать матрицы 4 × 4 и векторы-строки 1 × 4. Обратите внимание, что использование матриц двух указанных размеров подразумевает, что определены результаты следующих операций умножения матриц:
Умножение вектора-строки на матрицу. То есть, если v — это вектор-строка 1 × 4, а T — это матрица 4 × 4, произведение vT определено и представляет собой вектор-строку 1 × 4.
Умножение матрицы на матрицу. То есть, если T — это матрица 4 × 4 и R — это матрица 4 × 4, произведения TR и RT определены и оба являются матрицами 4 × 4. Обратите внимание, что произведение TR не обязательно равно RT, поскольку операция умножения матриц не коммутативна.
Для представления вектора-строки 1 × 4 в библиотеке D3DX, мы будем использовать классы векторов D3DXVECTOR3 и D3DXVECTOR4. Конечно, в классе D3DXVECTOR3 только три компоненты, а не четыре. Однако обычно подразумевается что четвертая компонента равна нулю или единице (более подробно это будет обсуждаться в следующем разделе).
Для представления матриц 4 × 4 в библиотеке D3DX, мы используем класс D3DXMATRIX, определение которого выглядит следующим образом:
typedef struct D3DXMATRIX : public D3DMATRIX { public: D3DXMATRIX() {}; D3DXMATRIX(CONST FLOAT*); D3DXMATRIX(CONST D3DMATRIX&); D3DXMATRIX(FLOAT _11, FLOAT _12, FLOAT _13, FLOAT _14, FLOAT _21, FLOAT _22, FLOAT _23, FLOAT _24, FLOAT _31, FLOAT _32, FLOAT _33, FLOAT _34, FLOAT _41, FLOAT _42, FLOAT _43, FLOAT _44); // получение элемента FLOAT& operator () (UINT Row, UINT Col); FLOAT operator () (UINT Row, UINT Col) const; // приведение типа operator FLOAT* (); operator CONST FLOAT* () const; // операторы присваивания D3DXMATRIX& operator *= (CONST D3DXMATRIX&); D3DXMATRIX& operator += (CONST D3DXMATRIX&); D3DXMATRIX& operator -= (CONST D3DXMATRIX&); D3DXMATRIX& operator *= (FLOAT); D3DXMATRIX& operator /= (FLOAT); // унарные операторы D3DXMATRIX operator + () const; D3DXMATRIX operator - () const; // бинарные операторы D3DXMATRIX operator * (CONST D3DXMATRIX&) const; D3DXMATRIX operator + (CONST D3DXMATRIX&) const; D3DXMATRIX operator - (CONST D3DXMATRIX&) const; D3DXMATRIX operator * (FLOAT) const; D3DXMATRIX operator / (FLOAT) const; friend D3DXMATRIX operator * (FLOAT, CONST D3DXMATRIX&); BOOL operator == (CONST D3DXMATRIX&) const; BOOL operator != (CONST D3DXMATRIX&) const; } D3DXMATRIX, *LPD3DXMATRIX;
Класс D3DXMATRIX наследует элементы данных от простой структуры D3DMATRIX, определенной следующим образом:
typedef struct _D3DMATRIX { union { struct { float _11, _12, _13, _14; float _21, _22, _23, _24; float _31, _32, _33, _34; float _41, _42, _43, _44; }; float m[4][4]; }; } D3DMATRIX;
Обратите внимание, что в классе D3DXMATRIX есть десятки полезных операторов для проверки равенства, сложения и вычитания матриц, умножения матрицы на скаляр, преобразования типов и — самое главное — перемножения двух объектов типа D3DXMATRIX. Поскольку умножение матриц так важно, приведем пример кода, использующего этот оператор:
D3DXMATRIX A(Е); // инициализация A D3DXMATRIX B(Е); // инициализация B D3DXMATRIX C = A * B; // C = AB
Другим важным оператором класса D3DXMATRIX являются скобки, позволяющие легко получить доступ к отдельным элементам матрицы. Обратите внимание, что при использовании скобок нумерация элементов матрицы начинается с нуля, подобно нумерации элементов массива в языке С. Например, чтобы обратиться к верхнему левому элементу матрицы, следует написать:
D3DXMATRIX M; M(0, 0) = 5.0f; // Присвоить первому элементу матрицы значение 5.0f.
Кроме того, библиотека D3DX предоставляет набор полезных функций, позволяющих инициализировать единичную матрицу D3DXMATRIX, транспонировать матрицу D3DXMATRIX и инвертировать матрицу D3DXMATRIX:
D3DXMATRIX *D3DXMatrixIdentity( D3DXMATRIX *pout // Матрица, инициализируемая как единичная ); D3DXMATRIX M; D3DXMatrixIdentity(&M); // M = единичная матрица D3DXMATRIX *D3DXMatrixTranspose( D3DXMATRIX *pOut, // Результат транспонирования матрицы CONST D3DXMATRIX *pM // Транспонируемая матрица ); D3DXMATRIX A(...); // инициализация A D3DXMATRIX B; D3DXMatrixTranspose(&B, &A); // B = транспонированная(A) D3DXMATRIX *D3DXMatrixInverse( D3DXMATRIX *pOut, // возвращает результат инвертирования pM FLOAT *pDeterminant, // детерминант, если необходим, иначе 0 CONST D3DXMATRIX *pM // инвертируемая матрица );
Функция инвертирования возвращает NULL, если переданная ей матрица не может быть инвертирована. Кроме того, в этой книге мы игнорируем второй параметр и всегда передаем в нем 0.
D3DXMATRIX A(...); // инициализация A D3DXMATRIX B; D3DXMatrixInverse(&B, 0, &A); // B = инвертированная(A)
netlib.narod.ru | < Назад | Оглавление | Далее > |