Главная » Программирование игр под Android » Фильтрация текстур – РАЗРАБОТКА ИГР ДЛЯ ОС ANDROID

0

Есть еще одна деталь, которую нам необходимо определить перед тем, как мы сможем использовать объект текстуры. Она связана с тем, что наш треугольник может занимать больше или меньше пикселов на экране по сравнению с тем, сколько пикселов есть в обозначенной зоне текстуры. Например, изображение Боба на рис. 7.10 имеет размер 128 х 128 пикселов. Наш треугольник занимает половину этого изображения, так что он использует 128 х 128/2 пиксела из текстуры (текстурные пикселы также называются текселы). Когда мы нарисуем на экране треугольник с координатами, которые описали в предыдущем фрагменте кода, он будет занимать 320 х 480 / 2 пикселов. На экране мы используем гораздо больше пикселов по сравнению с тем, что перенесли из зоны текстуры. Естественно, все может быть и наоборот: мы используем меньше пикселов на экране, чем на выделенной зоне текстуры. Первый случай называется магнификацией, а второй – минификацией. В каждом из них нам необходимо сообщить OpenGL ES, как нужно увеличивать или уменьшать текстуру. В терминологии OpenGL ES соответствующие механизмы называются фильтрами минификации и магнифи-кации. Эти фильтры являются свойствами объекта текстуры, как и сами данные изображения. Чтобы их установить, необходимо сначала проверить, привязан ли объект текстуры с помощью glBindTexture. Если это так, устанавливаем их следующим образом:

В обоих случаях используем метод GL10 .glTexParameterf , который устанавливает свойства текстуры. В первом случае мы определяем фильтр минификации, а в другом – фильтр магнификации. Первый параметр в этом методе – тип текстуры, который в нашем случае по умолчанию равен GL10 .GL TEXTURE 2D. Второй параметр сообщает методу, какое свойство мы хотим установить. В нашем случае это GL10.GL TEXTURE MIN FILTER и GL10.GL TEXTURE MAG FILTER. Последний параметр указывает тип фильтра, который должен быть использован. Здесь у нас есть два варианта: GL10. GLJEAREST и GL10. GL LINEAR.

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

На рис. 7.12 показана разница между этими двумя типами фильтров.

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

Рис. 7.12. Фильтр GL1O.GL NEAREST делает изображение мозаичным (слева), фильтр GL10.GL LINEAR немного сглаживает изображение (справа)

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

О – это специальный ID, который сообщает OpenGL ES, что следует отвязать текущий привязанный объект. Если мы хотим использовать текстуру для рисования треугольников, нам, естественно, нужно заново ее привязать.

Удаление текстур

Полезно также знать, как удалить объект текстуры из видеопамяти, если он нам больше не нужен (так же, как мы используем Bitmap. гесусе, чтобы освободить память рисунка). Это можно сделать с помощью следующего фрагмента:

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

Полезный фрагмент кода

Вот (для справки) полный пример кода, предназначенный для объекта текстуры, загрузки графических данных и установки фильтров на Android:

Совсем неплохо. Самое важное здесь – заново использовать рисунок Bitmap, когда мы закончим. Иначе мы будем впустую тратить память. Данные нашего изображения надежно хранятся в видеопамяти в объекте текстуры (до тех пор пока контекст не будет утерян и нам не понадобится заново все загрузить).

Активация текстурирования

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

Это должно быть вам уже знакомо. Когда мы включали/выключали свойства вершины ранее, мы использовали метод gl Enabl е1ientState/gl Di sabl eCl i entState. Как я говорил раньше, это все особенности OpenGL. На самом деле есть причины, почему они не включены в glEnable/glDisab1e, но не будем в это углубляться. Просто запомните, что надо использовать gl Enabl eCl i entState /gl Di sabl eCl i entState , чтобы включить/выключить свойства вершины, a glEnableC /glDisable для всех других состояний OpenGL, например текстурирования.

Все вместе

Теперь мы наконец-то можем написать небольшой пример, который соединит все вместе. В листинге 7.7 показан отрывок из файла с исходным кодом TexturedTriangleTest. java. Здесь приведена только нужная нам часть с классом TexturedTriangleScreen.

Листинг 7.7. Отрывок из TexturedTriangleTest.java: текстурирование треугольника

Я решил поместить загрузку текстуры в метод loadTexture, который просто использует имя загружаемого изображения. Метод возвращает ID-объект текстуры, сгенерированный OpenGL ES, который мы будем прменять в методе present  для привязки текстуры.

Описание нашего треугольника вряд ли вас удивит, мы просто добавили координаты текстур к каждой вершине.

Метод present  делает то же, что и всегда: очищает экран и устанавливает матрицу проекции. Затем активируем ассоциирование текстур с помощью вызова glEnableO и привязываем наш объект текстуры. Оставшаяся часть такая же, как всегда: включение свойств вершины, которые мы хотим использовать, сообщение OpenGL ES, где их можно найти и какие шаги при этом использовать, и, наконец, рисование треугольника с вызовом gl DrawArrays . На рис. 7.13 показаны результаты выполнения предыдущего кода.

Рис. 7.13. Ассоциирование текстуры Боба с треугольником

Осталась еще одна очень важная вещь, которую мы не обсудили. Все растровые изображения, которые мы загружаем, должны иметь ширину и высоту в степени 2. Это аксиома, и если ей не следовать, возникнут проблемы.

Что это значит? Изображение Боба, которое мы использовали в нашем примере, имеет размер 128 х 128 пикселов. 128 – это 2 в седьмой степени (2 х 2 х 2 х 2 х 2 х 2 х 2). Другие размеры изображения могут быть 2 х 8,32 х 16,128 х 256 и т. д. Существует также предел того, насколько велики могут быть изображения. К сожалению, он варьируется в зависимости от возможностей аппаратуры, на которой запущено изображение. Насколько мне известно, стандарт OpenGL ES 1.x не описывает минимальный поддерживаемый размер текстуры. Тем не менее, исходя из моего опыта, текстура 512×512 пикселов работает на всех современных устройствах Android (и, скорее всего, будет работать на всех будущих). Я даже позволю себе предположить, что размер 1024 х 1024 также подойдет.

Еще один момент, который мы до сих пор игнорировали, – это глубина цвета текстур. К счастью, метод GLUti 1 s. texImage2D, который мы использовали для загрузки данных нашего изображения в центральный процессор, достаточно успешно справляется с этим. OpenGL ES может работать с такой глубиной цвета, как RGBA8888, RGB565 и т. д. Мы всегда должны пытаться использовать наименьшую возможную глубину цвета, чтобы уменьшить необходимую пропускную способность. Для этого мы можем использовать класс Bi tmapFactory. Opti ons, как в предыдущих главах, чтобы, например, загрузить изображение RGB888 или изображение RGB565. Когда мы загрузили экземпляр класса Bitmap с той глубиной цвета, которая нам нужна, мы используем GLUti 1 s. texImage2D, который проверяет, получил ли OpenGL ES данные изображения в верном формате. Конечно, вы всегда должны проверять, сказывается ли уменьшение глубины цвета негативно на внешнем виде игры.

Класс Texture

Чтобы уменьшить количество кода, необходимого для следующих примеров, я написал небольшой вспомогательный класс Texture. Он загрузит изображение из ресурса и создаст из него объект текстуры. У него также есть несколько удобных методов, чтобы привязать текстуру и чтобы избавиться от нее. Код приведен в листинге 7.8.

Листинг 7.8. Texture.java, небольшой класс Texture для OpenGL ES package com.badlogic.androidgames.framework.gl;

Единственный интересный компонент этого класса – метод reload, который мы можем использовать, когда контекст OpenGL ES утерян. Обратите также внимание, что метод setFiltersO будет работать только в том случае, если Texture привязан. В противном случае он установит фильтры текущей привязанной текстуры.

Мы могли бы также написать небольшой вспомогательный метод для обработки буфера наших вершин. Но перед этим нужно обсудить еще одну деталь: индексированные вершины.

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

По теме:

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