Андроиды в дельфинарии

от автора

Приветствую всех любителей тех устройств, что помещаются в карман, а также тех, кто держит свой карман шире 7".

Сейчас мы займемся искусством программирования кросс-платформенных графических приложений, то есть таких приложений, которые работают на мобильной платформе (смартфоны и планшеты Android) и под Windows (стационарные PC, ноутбуки, нетбуки, планшеты). При этом наши приложения будут графическими, графика основана на OpenGL (OGL) и его мобильном варианте OpenGL ES (GLES).
Я использую Embarcadero Delphi XE7, важная особенность – в этом проекте я не использую библиотеку FireMonkey, мы будем писать все “с нуля” и на “голых API”, как в старые добрые времена.

Предлагаю сразу разделить работу пополам:
— я пишу кросс-платформенную графическую библиотеку, рассматриваю примеры её использования, расписываю детали реализации, отвечаю на вопросы;
— ваша часть не менее ответственна: от вас мне нужен тест демок на различных мобильных устройствах, рапорты о выполнении, отзывы и критика, новые идеи и свежее мясо новые пользователи как библиотеки так и собственно приложений.

1. Первая демка

Android mc.apk 3.8 MB yadi.sk/d/UaGYqsu9ff8Dd
Windows mc.zip 1.9 MB yadi.sk/d/tBKQxaV7ff8KW
Исходные тексты в репо: sourceforge.net/p/delphioga/code/ci/default/tree

image

В первой версии программа не хитрая – она просто выводит на экран 4096 угловатых разноцветных шариков и позволяет полетать мимо них в режиме “свободной камеры”. Сферы я раскрасила по принципу цветового пространства RGB, ещё они вращаются. На этом примере я хочу рассмотреть методы построения 3D примитивов (в частности сфер) и приёмы оптимизации отрисовки (Frustum сulling, детализация объектов).
Но нам никак не обойтись без небольшой вводной части.

2. Инструкция по эксплуатации, смартфон/планшет Android
1. Устанавливаем mc.apk, это архив инсталляции программы. Если у вас есть вопросы как это сделать, я готова помочь.
2. При установке apk возможно предупреждение, что программа требует доступа к Internet. На самом деле программа скомпилирована в режиме Debug, поэтому ей потенциально нужен доступ к локальной сети для возможности работы отладчика (gdbserver) и консоли логов logcat. Логи нам еще потребуются. Из самой программы к сети я не обращаюсь никак, там есть только рисование графики на экране.
3. После установки у вас добавится новый ярлычок на Рабочем столе “mc”. Запускаем программу. Любуемся на заставку — огонек FM (я пока не меняла иконки мобильного проекта Delphi по умолчанию). Обращаем внимание на время запуска приложения, сколько оно у вас приблизительно в секундах и их долях? Мы можем сравнить это с временем загрузки примеров FM приложений, пока что сравнение в нашу пользу.
4. Вот вы и на месте, добро пожаловать. Используйте ваши пальцы и тачскрин для изменения направления взгляда и направления движения. Справа вверху есть парочка экранных кнопок – вперед и назад. Если у вас 2 руки, вы можете одновременно двигаться и поворачиваться. Для этого потребуется определенная сноровка, уж чего-чего, а простой жизни я не обещала. Думайте о PVP.
5. При переключении в другое приложение или “засыпании” планшета (давайте мобильное устройство именовать планшетом, потому что у меня планшет) программа приостановит отрисовку графики (контекст GLES и само окно приложения удаляются, так положено делать на Android), однако сама программа не прекратит работу. При переключении обратно в приложение или “пробуждении” планшета окно и контекст будут созданы заново, мы продолжим наше путешествие с места остановки. Следует обращать внимание на этот нюанс при тестировании, некоторые игры не умеют корректно “восстанавливаться”, мы же должны уметь.
6. Поверните планшет горизонтально, потом вертикально. Работу приложения следует проверять в каждом из этих двух режимов. Разумеется такой фокус сработает, только если у вас ориентация дисплея устройства установлена в “авто”.
7. Выйти из демки просто – нажмите системную кнопку “назад”.
8. Напишите в комментариях к статье тип мобильного устройства, которое вы применяли (фирма-производитель, модель), я постараюсь отыскать его характеристики, типы CPU и GPU, версию OS. Эти данные я включаю в файл hardware.txt в репо.

3. Инструкция по эксплуатации, Windows
1. Распаковываем архив zip. Не удивляемся объему exe файла, демка скомпилирована в режиме Debug, в релизе exe весит 1.5 MB. Запускаем mc.exe.
Никаких системных предупреждений о использовании сети, как в Android не будет, потому что сеть в демке не используется, на PC отладчик и логи работают локально.
2. Вот вы и на месте, добро пожаловать. Для изменения направления взгляда и направления движения “потащите” экран при нажатой левой кнопке мышки (ЛКМ). Для перемещения в пространстве работают клавиши [WASD] на клавиатуре (либо стрелки, либо стрелки на NumPad). Используя [WASD] думайте о PVP. Экранные кнопки для движения вперед-назад тоже есть, они кликабельны. [F1] выводит справку, [ESC] позволяет выйти из программы.
3. Обратите внимание на второе окно (при запуске программы на панели управления появляется два окна), это консоль отладки. Подобную консоль для Android (logcat) мы рассмотрим позже. Вывожу я там всякое-разное, пока нам интересны только GPU Vendor, Renderer (это фирма-производитель и тип вашей видеокарты, потребуются нам в случае если что-то не работает, но это врядли), и Open GL version. Если версия OGL ниже 3.0, то я могу сказать, что некоторые будущие возможности библиотеки не пойдут на вашей старой видеокарте. Впрочем, прикладное приложение может содержать 2 ветки реализации таких возможностей и работать в любом случае.
4. VSYNC в этом примере выключен, FPS может быть куда больше 60 Гц (попробуйте отвернуться от видимых объектов), нагрузка на GPU и CPU максимальна. Я так делаю для тестирования скорости отрисовки фрейма, если включить VSYNC нагрузка станет нормальной.
5. Размеры окна изменяются произвольно, но угол обзора не превышает 180.

image

4. Отладочный вывод на экран
На скриншотах слева вверху есть некоторые желтые буквы и цифры.
FPS – среднее число кадров в секунду, наш главный инструмент в оценке быстродействия рисования. Под Android VSYNC включен, FPS лимитирован частотой обновления экрана (60 Гц), впрочем я так подогнала нагрузку на GPU в демо, что на большинстве мобильных устройств FPS будет “проседать”. Это не страшно пока управление и анимация остаются адекватными. Под Windows же VSYNC выключен, FPS не имеет лимита;
TDF – среднее время отрисовки одного фрейма в миллисекундах, по сути величина обратная FPS; она нужна чтобы понимать “тайминг” — какого порядка интервалы времени у нас фигурируют для рисования кадра; при FPS 60 Гц это время около 17 мс;
NFR – число отрисованных фреймов от старта приложения; при FPS 60 Гц в первую же секунду эта цифра достигнет 60;
T – время в мс от старта приложения, его я использую как аргумент для функций анимации, в примере от него зависит вращение сфер;
POS — координаты XYZ камеры в 3D мире, в начале оси расположены так: X направо, Y вверх, Z на нас;
AH, AV — углы поворота камеры относительно горизонтали и вертикали в градусах; о угле крена лучше поговорить отдельно;
N – общее число объектов в Вселенной;
NV – столько объектов целиком или частично попадают в область видимости (фрустум, усеченная пирамида поля зрения камеры);
HD – столько ближних объектов отображаются с несколько лучшим качеством отрисовки, дальние объекты рисуются попроще.

5. Как выглядит процесс разработки
Я подключаю планшет к PC под Windows USB-кабелем (можно и через Wi-Fi). Сначала пишу платформенно-зависимый код неких функций для Android, запускаю программу на планшете. Эта часть работы самая сложная, потому что приложение сравнительно долго компилируется и запускается на планшете. Отладка доступна (точки остановки, пошаговое выполнение). Также использую отладочный вывод приложения в logcat, смотреть логи могу прямо на PC в реальном времени. Когда на планшете заработало, я пишу платформенно-зависимый вариант кода функций для Windows. Это уже проще. После этого начинается самое интересное – основную часть программы я пишу универсальным кодом вызывая одноименные платформенные функции, проверяю на PC и лишь изредка заливаю на планшет, как правило, там все работает.

6. Под капотом и под катом
Заглянем немного в исходные тексты.

В папке common у меня лежит собственно библиотека. Начнем с файла Draw.pas. На чем основана кросс-платформенная графика? Под Windows я использую модуль OpenGL.pas, но только те функции, которые имеют аналоги в GLES под Android (модули Androidapi.Egl.pas, Androidapi.Gles.pas, Androidapi.Gles2.pas).

uses
Types,SysUtils,
{$IFDEF Android}
Androidapi.Egl, Androidapi.Gles, Androidapi.Gles2,
{$ENDIF}
{$IFDEF MSWINDOWS}
Winapi.OpenGL,
{$ENDIF}
Vectors, Colors, Textures, DrawPolyhedron, DrawSphere;

Там где OGL и GLES совпадают разницы в синтаксисе мало, вот разве что glOrtho пришлось подровнять. При помощи директив условной компиляции мы будем описывать платформенно-зависимую реализацию.

{$IFDEF ANDROID}
procedure glOrtho (left, right, bottom, top, zNear, zFar: GLfloat);
begin
glOrthof(left, right, bottom, top, zNear, zFar);
end;
{$ENDIF}

Что ещё не совпадает? На GLES нет glBegin/glEnd и соответственно всего связанного с ними семейства функций. Это не страшно, будем рисовать в стиле OGL 2.0 передавая за один раз указатели на массивы вершин (нормалей, цветов, текстурных координат). Например, простейший треугольник можно нарисовать так (цвет текущий, нормалей и текстур нет):

procedure Triangle(p1, p2, p3: TV3); overload;
begin
SetLength(ap3, 3);
ap3[0] := p1;
ap3[1] := p2;
ap3[2] := p3;
glVertexPointer(3, GL_FLOAT, 0, @ap3[0]);
glDrawArrays(GL_TRIANGLES, 0, Length(ap3));
end;

Чтобы нарисовать множество треугольников 3D фигуры не следует вызывать процедуру Triangle много раз. Следует сложить все вершины всех треугольников в один массив и нарисовать их единственным вызовом glDrawArrays. Эта функция используется в текущем демо для рисования каждой сферы, как с GL_TRIANGLES так и с GL_TRIANGLE_STRIP:

// отобразить готовый массив вершин c нормалями
procedure DrawAVNT(avn: TAVertexN; met:GLenum; Position,Rotation,Scale: TV3);
begin
glPushMatrix;
Transform(Position,Rotation,Scale);
glVertexPointer(3, GL_FLOAT, SizeOf(TVertexN), avn[0].V);
glNormalPointer(GL_FLOAT, SizeOf(TVertexN), avn[0].N);
glDrawArrays(met,0,Length(avn));// GL_TRIANGLES
glPopMatrix;
end;

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

ссылка на оригинал статьи http://habrahabr.ru/post/258379/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *