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

0

Наш план действий будет таким – загрузить файл в память полностью и создать строку для каждой его строки. Мы также создадим временные массивы чисел с плавающей точкой для всех позиций вершин, координат текстур и нормалей, которые мы собираемся загрузить. Их размер равен количеству строк OBJ-файла, умноженному на количество компонент атрибута, – два для координат текстур или три для нормалей. Благодаря этому мы выделим памяти больше, чем необходимо, но это лучше, чем выделять память для новых массивов всякий раз, когда их понадобится пополнить.

То же самое мы сделаем для индексов, определяющих каждый треугольник. Поскольку формат OBJ является индексированным, мы не можем передать эти индексы непосредственно в класс Vertices3.

Причиной этого является тот факт, что атрибуты вершины могут быть использованы повторно несколькими вершинами, поэтому складываются отношения один ко многим, что не разрешается OpenGL ES. Поэтому мы будем использовать неиндексированный экземпляр класса Verti ces3 и просто дублировать вершины. Такой подход подойдет для наших нужд.

Посмотрим, как мы можем реализовать все это. Код этого класса содержится в листинге 11.12.

Листинг 11.12. Класс ObjLoader.java. простой класс, предназначенный для загрузки подмножества формата 0BJ

Первое, что мы делаем, – открываем в потоке InputStream файл с моделью, определяемый параметром fi1е. Потом в методе readLines  (определенном далее) мы считываем все строки этого файла. Основываясь на количестве строк, мы выделяем память для массивов чисел с плавающей точкой, которые будут хранить компоненты осей х, у и z каждой нормали вершин, а также и- и -координаты текстур каждой вершины. Поскольку мы не знаем, сколько именно вершин мы увидим в файле, просто выделяем больше памяти, чем требуется. Каждый атрибут вершины хранится в последовательных элементах трех массивов. Позиция первой считанной вершины представлена элементами массива vertices[0], vertices[1] и vertices[2] и т. д. Мы также отслеживаем индексы при определении треугольников для каждого из трех атрибутов вершины. В дополнение у нас есть несколько счетчиков для отслеживания того, как много всего мы уже загрузили.

Далее у нас есть цикл, которых проходит по всем строкам файлов.

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

Мы делаем то же самое для нормалей и координат текстур:

В этом коде каждая вершина треугольника (названного здесь face (ребро) из-за терминологии формата OBJ) определяется тройкой индексов в массивах позиции вершин, координат текстур и нормалей. Индексы координат текстур и нормалей могут быть опущены, поэтому нам нужно следить за ними. Индексы также могут быть отрицательными, в этом случае нам придется добавлять их к количеству позиций/координат текстур/нормалей, загруженных ранее. Этим занимается метод getlndex.

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

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

Последнее, что мы делаем, – создаем экземпляр класса Vertices3 и устанавливаем вершины.

Остальная часть метода посвящена обработке исключений и закрытию потока InputStream.

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

Наконец, рассмотрим метод readlines, который просто считывает каждую строку файла и возвращает их все как список строк.

Чтобы загрузить OBJ-файл из ресурса, мы можем использовать класс Ob j Loader следующим образом:

Довольно прямолинейно после всей этой чехарды с индексами, не правда ли? Для отрисовки этого экземпляра класса Vertices3 нам необходимо знать, сколько он имеет вершин. Расширим класс Verti ces3 еще раз, добавив два метода, возвращающих количество вершин и количество индексов, которые определены в объекте в данный момент. Код этих методов содержится в листинге 11.13.

Листинг 11.13. Фрагменты класса Vertices3.java, получение количества вершин и индексов

Для количества индексов мы просто возвращаем границу ShortBuffer, хранящего индексы. Для количества вершин мы делаем то же самое. Однако, поскольку граница сообщается в виде количества чисел с плавающей точкой, определенных в буфере FloatBuffer, нам придется делить его на размер вершины.

Поскольку мы храним это количество байтов в параметре vertexSize, мы делим этот член класса на 4.

Использование класса OBJ Loader

Чтобы продемонстрировать работу загрузчика файлов OBJ, я переписал последний пример и создал новый тест, который называется ObjTest, а также экран ObjScreen. Я скопировал весь код из предыдущего примера и изменил только одну строку конструктора класса ObjScreen:

Поэтому вместо использования метода createCube (который я убрал) теперь мы напрямую загружаем модель из файла с расширением OBJ, который называется cube.obj. В программе Wings3D я создал копию куба, которую мы ранее создавали программно в методе createCube . Она имеет те же позиции вершин, текстурные координаты и нормали, что и созданная вручную версия. Вас не должно удивлять то, что результат работы программы ObjTest выглядит точно так же, как и результат работы Eul erCameraTest. Поэтому я не буду приводить скриншот.

Несколько замечаний по загрузке моделей

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

Обработка строк в ОС Android по определению медленная. OBJ – это формат, использующий неформатированный текст, поэтому он требует больших затрат времени на свое преобразование. Это отрицательно повлияет на время загрузки. Вы можете обойти эту проблему, преобразуя ваши OBJ-модели в пользовательский бинарный формат. Вы можете, например, сериализовать массив verts таким образом, что мы заполняем его в методе ObjLoader. load О.

Формат OBJ имеет гораздо больше особенностей, чем мы рассмотрели. Если вы хотите расширить наш простой загрузчик, посмотрите спецификацию формата в Интернете. Добавить новую функциональность должно быть легко.

OBJ-файл часто предоставляется вместе с файлом материала. Этот файл определяет цвета и текстуры, используемые группами вершин, которые описаны в OBJ-файле. Нам не понадобится эта функциональность, поскольку мы знаем, какую текстуру использовать для конкретного OBJ-файла. Для создания более надежного загрузчика вам потребуется заглянуть в спецификацию файлов материала.

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

По теме:

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