Главная » Программирование игр под Android » СНОВА МАТРИЦЫ И ПРЕОБРАЗОВАНИЯ – РАЗРАБОТКА ИГР ДЛЯ ОС ANDROID

0

 

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

Умножение матрицы на единичную матрицу не повлияет на саму матрицу.

OpenGL ES предоставляет три типа матриц.

Матрица проекций. Используется для установки формы и размера окна просмотра. Эти параметры управляют типом проекции и тем, какая часть мира будет показываться пользователю.

Модельно-видовая матрица. Применяется для преобразования моделей в модельном пространстве, а также для размещения модели в пространстве мира.

Матрица текстур. Снова не обращаем на нее внимания, поскольку с ней нельзя корректно работать на многих устройствах.

Теперь, когда мы работаем в трехмерном пространстве, у нас есть гораздо больше настроек. К примеру, мы можем не только поворачивать модель вокруг оси z, как мы это делали с Бобом, но и вокруг любой оси. Единственное важное изменение – это появление дополнительной z-оси, которую также можно использовать для размещения объектов. На самом деле мы уже работали в 3D ранее, когда отрисовывали Боба мы просто игнорировали z-ось. Теперь мы можем осуществить и более масштабные задумки.

Матричный стек

До этого момента мы использовали матрицы в OpenGL ES примерно так:

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

В этом фрагменте кода действия производятся над модельно-видовой матрицей. Сначала загружается единичная матрица для того, чтобы очистить модельно-видовую матрицу перед вызовом. Далее эта матрица умножается на матрицу переноса и матрицу поворота. Важно сохранить именно такой порядок умножения, поскольку он определяет порядок применения преобразований к вершинам сетей. Последнее определенное нами преобразование будет применено к вершинам в первую очередь. В предыдущем случае мы сначала поворачиваем каждую вершину на 45° вокруг оси у. Далее все вершины перемещаются вдоль оси 2 на -10 единиц.

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

В данный момент мы применяем лишь один элемент этого стека: вершину стека (ВС). ВС стека матриц применяется в OpenGL ES для преобразования вершин, независимо от того, идет ли речь о проекционной матрице или модельно-видовой матрице. Любая матрица, располагающаяся ниже ВС, не оказывает никакого влияния на точки, ожидая, пока она не станет ВС. Как же управлять этим стеком?

В OpenGL ES есть два метода, с помощью которых можно поместить в стек или вытолкнуть из него текущую ВС:

Аналогично методу g1Trans1atef  и подобным ему эти методы всегда работают с текущим активным матричным стеком, который устанавливается с помощью метода gMatri xMode .

Метод gl PushMatri х принимает текущую ВС, копирует ее. Метод gl PopMatri х принимает текущую ВС и поднимает ее, удаляя вершину из стека. После этого элемент, находящийся под вершиной, становится новой ВС. Метод gl PopMatri х принимает текущую ВС и выталкивает ее из стека. Напишем небольшой пример:

До этого момента в стеке видовых матриц существовала всего одна матрица. Сохраним ее:

Теперь мы сделали копию текущей ВС и сместили вниз предыдущую ВС. У нас в стеке теперь есть две матрицы, каждая из которых кодирует параллельный перенос по оси z на -10 единиц.

Поскольку матричные операции всегда работают с ВС, теперь в верхней матрице закодированы операции масштабирования, поворота и параллельного переноса. Матрица, которую мы сместили вниз, по-прежнему содержит лишь операцию параллельного переноса. При отрисовке сети, заданной в пространстве моделей, вроде нашего куба, сначала она будет масштабирована по оси у, потом повернута по оси у, а затем перенесена на -10 единиц по оси z. Вытолкнем из стека его вершину:

Это действие удаляет ВС, а матрица под ней становится новой ВС. В нашем примере таковой является оригинальная матрица переноса. После вызова этого метода в стеке снова находится только одна матрица – та, которую мы инициализировали в самом начале примера. Если объект будет отрисован сейчас, он будет лишь перенесен на -10 единиц по оси z. Матрицы, содержащей операции масштабирования, поворота и переноса, больше не существует, поскольку она была вытолкнута из стека. На рис. 10.13 показано, что произойдет со стеком матриц при выполнении предшествующего кода.

Рис. 10.13. Манипуляции с матричным стеком

Для чего можно использовать матричный стек? Первое, для чего он может быть использован, – запоминание преобразований, которые должны быть применены для всех объектов мира. Предположим, мы хотим, чтобы все объекты мира имели смещение на 10 единиц по каждой оси. Мы можем сделать следующее:

Этот шаблон мы используем и далее, когда будем обсуждать создание системы камер в 3D. Позиция камеры и ее ориентация часто кодируются в виде матрицы. Мы загрузим эту матрицу камеры, которая преобразует все объекты так, чтобы мы смогли увидеть их с позиции камеры. Однако есть кое-что получше матричного стека.

Источник: Mario Zechner / Марио Цехнер, «Программирование игр под Android», пер. Егор Сидорович, Евгений Зазноба, Издательство «Питер»

По теме:

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