Главная » Разработка для Windows Phone 7 » Трансформации матриц Windows Phone 7

0

Традиционно двухмерные графические системы поддерживают операции, называемые трансформациями. По сути своей, это математические формулы, применяемые к координатам (x, y) для получения новых координат (x, y). Полностью обобщённые трансформации потенциально могут быть очень сложными, но двухмерные среды разработки графических элементов часто ограничиваются подмножеством трансформаций, называемым аффинными («не бесконечными») преобразованиями. К таким преобразованиям относятся и линейные трансформации.

Линейные преобразования для переменных x и y выглядят следующим образом:

х’ = ахх + Ьху

 у’ = аух + Ьуу

где индексированные a и b – это константы, определяющие конкретное преобразование. Как видите, x’ и у’ являются функциями x и y, и это очень простые функции. В них переменные всего лишь умножаются на константы, и результаты этого умножения суммируются; x и y даже не перемножаются, к примеру.

В реализации аффинного переноса добавляется еще одна константа, которая ни на что не умножается:

х’ = ахх + bху + сх

у’ = аух + Ьуу + Су

Очень часто некоторые из этих констант равны нулю. Если ax и by равны 1, и bx и ay равны нулю, формулы представляют тип преобразования, называемый переносом:

X ‘ = X + cx

у’ = у +Су

Это преобразование просто обеспечивает смещение объекта в другое место, наподобие того как это было в приложении OneFingerDrag в начале этой главы.

Если bx и ay равны нулю, и cx и cy тоже равны нулю, тогда мы получаем формулы для масштабирования:

Х ‘ = ax x

у’ = ЬуУ

Координаты умножаются на коэффициенты, что обусловливает увеличение или уменьшение размеров объектов.

Четыре множителя можно заменить синусом и косинусом определенного угла:

х’ = cos(?)x — sin(?)y

у’ = sin(?)x + cos(?)y

Эти уравнения описывают вращение точки вокруг заданного центра на а градусов. Если всем четырем константам задать значения, не описываемые тригонометрическими функциями, уравнения будут описывать трансформацию наклонением, которая превращает квадрат в параллелограмм. Но это настолько же странно, насколько странные сами аффинные преобразования: они никогда не сделают прямую кривой или параллельные линии не параллельными. В результате аффинных преобразований координаты никогда не станут бесконечными.

Для применения трансформации к точке с координатами (x, y) точку представляют как матрицу 1×3 с 1 в качестве третьего члена и выполняют умножение матриц:

Перенос, масштабирование и вращение – это самые распространенные типы трансформаций. Их можно комбинировать. Для упрощения вычислений трансформации часто представляют в виде матриц 3×3:

Существенное преимущество представления трансформаций с помощью матриц ощущается при комбинировании трансформаций, что эквивалентно умножению матриц, а эта операция всем хорошо известна. Также общеизвестно, что умножение матриц является некоммутативной операцией, т.е. порядок умножения имеет значение.

Например, необходимо применить к объекту трансформацию масштабирования, чтобы сделать его больше, и затем подвергнуть его трансформации перемещения, чтобы передвинуть в другое место. Если поменять местами эти две операции, т.е. сначала переместить объект и затем изменить его размер, результат будет иным, потому что масштабирование будет применяться и к коэффициентам переноса.

Трансформации в двухмерном пространстве описываются матрицами 3×3, и трансформации в трехмерном пространстве описываются матрицами 4×4. Имеется очень веское основание тому, почему матрица должна иметь на одно измерение больше, чем описываемое координатное пространство – перемещение. Перемещение является очень базовой и широко применяемой трансформацией, но оно не может быть описано линейным преобразованием, в котором координаты x и y просто умножаются на некоторые коэффициенты. Для представления перемещения как линейного преобразования должно быть добавлено еще одно измерение. Перемещение в двухмерном пространстве – это сдвиг в трехмерном, и поэтому двухмерная точка преобразовывается в трехмерную добавлением единичного значения Z для умножения на матрицу.

Третий столбец матрицы двухмерного аффинного преобразования всегда включает два нуля и 1 в нижнем правом углу. Это то что делает данное преобразование аффинным. (Неаффинные двухмерные преобразования обсудим в конце данной главы.)

После такого длинного вступления удивительно узнать, что XNA в отличие от практически всех остальных графических сред программирования не поддерживает структуру, которая инкапсулирует матрицу трансформации 3×3. В XNA матрицы обычно используются для трехмерной графики, поэтому XNA-структура Matrix (Матрица) инкапсулирует матрицу 4×4, которая подходит для трехмерной графики, но несколько избыточна для описания двухмерных объектов.

Хотя структура Matrix может использоваться с двухмерной графикой – и ее очень удобно применять для составных трансформаций – двухмерный XNA не обеспечивает особой поддержки трансформаций, кроме существенно более развернутой версии вызова метода Begin класса SpriteBatch:

spriteBatch.Begin(SpriteSortMode.Deferred, null, null, null, null, null, matrix);

При использовании данной формы вызова Begin объект Matrix будет оказывать влияние на все вызовы Draw и DrawString до тех пор, пока не будет вызван End. Это может быть очень полезным для применения трансформации к группе графических объектов.

Трансформации к объектам Vector2 могут также применяться «вручную» посредством нескольких версий статического метода Vector2.Transform.

Элементы главной диагонали единичной матрицы равны 1, умножение на нее не приводит к трансформации:

Структура Matrix поддерживает очень много статических методов для создания объектов Matrix, представляющих различные типы трансформаций. Все они созданы для трехмерной графики. Рассмотрим, как можно использовать наиболее базовые из них для двухмерной графики:

Matrix matrix = Matrix.CreateTranslation(xOffset, yOffset, 0); Matrix matrix = Matrix.CreateScale(xScale, yScale, 1); Matrix matrix = Matrix.CreateRotationZ(radians);

В качестве последнего аргумента первых двух методов обычно используются коэффициенты переноса или масштабирования для оси Z трехмерного координатного пространства. Обратите внимание, во втором случае я задал третий аргумент равным 1, а не 0. 0 подходит для большинства целей, но если когда-либо вам понадобится инвертировать матрицу, нулевой коэффициент масштабирования испортит все. Также заметьте, что в имени третьего метода упоминается ось Z. Этот метод должен вычислять угол поворота вокруг оси Z для описания вращения в двухмерной плоскости XY.

Структура Matrix поддерживает арифметические операторы, поэтому матрицы могут без труда перемножаться для реализации составных трансформаций. Чаще всего умножение матриц используется для представления масштабирования или вращения вокруг определенной точки.

Предположим, у нас имеется точка, представленная как объект Vector2 под именем center. Требуется вычислить матрицу для описания вращения вокруг этой точки на angle градусов. Начинать следует с перемещения точки center в начало координат, затем применяется вращение (или масштабирование) и еще одно перемещение для возвращения center в исходное положение:

Matrix matrix = Matrix.CreateTranslation(-center.X, -center.Y, 0); matrix *= Matrix.CreateRotationZ(angle);

matrix *= Matrix.CreateTranslation(center.X, center.Y, 0);

Обратите внимание на операторы умножения.

Вместо того, чтобы создавать объекты Matrix с помощью статических методов структуры Matrix, все эти поля можно задать по отдельности (или задать их все в конструкторе с 16 аргументами). Используемые нами ранее индексированные константы соответствуют этим ячейкам:

Структура Matrix в XNA включает 16 открытых полей типа float, которые представляют все 16 ячеек матрицы 4×4. Эти поля именованы соответственно строке и столбцу соответствующей ячейки в матрице:

Поле M11 – это горизонтальный коэффициент масштабирования, и M22 – вертикальный; M41 – горизонтальный коэффициент переноса, и M42 – вертикальный. Уравнения двухмерных аффинных преобразований можно переписать с использованием имен полей структуры Matrix:

х’ = M11* х + М21 * у + М41

 у’ = М12 * х + М22 * у + М42

Знание взаимоотношений между этими полями и трансформациями может помочь в извлечении данных из структуры Matrix или создании сокращенных реализаций, которые не включают создания новых объектов Matrix и их перемножения. Некоторые из этих методик будут продемонстрированы далее в этой главе.

Источник: Чарльз Петзольд, Программируем Windows Phone 7, Microsoft Press, © 2011.

По теме:

  • Комментарии