Портирование Android-Приложения На Webgl



Идея портирования Android-приложения на WebGL Сейчас WebGL поддерживается практически любым устройством и работает достаточно стабильно и быстро даже на мобильных устройствах, поэтому было очень интересно попробовать что-то реализовать с помощью этой технологии.

У нас уже есть большой опыт работы с OpenGL ES 2.0 в Android — мы создали довольно много различных живых 3D-обоев.



Портирование Android-приложения на WebGL

Мы создавали эти приложения без использования готовых сторонних движков (например, Unity) или высокоуровневых фреймворков для работы с OpenGL (таких как libGDX).

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

WebGL основан на OpenGL ES 2.0, поэтому процесс переноса обоев достаточно прост и понятен.



Фреймворк рендеринга

Как и в исходном коде Java, реализованы базовые классы.

Базовый рендерер И БазовыйШейдер .

Было решено использовать классы ECMAScript 2015, поскольку такая нотация упрощает читаемость кода, а единственный браузер, не поддерживающий JS-классы, — это IE11. Базовый рендерер содержит код для создания контекста WebGL, инициализации, отслеживания изменения размера окна и т. д. Также он содержит пустые «заглушки» для рендеринга сцены.

БазовыйШейдер содержит код для компиляции и использования шейдеров.

Сам рендеринг сцены и загрузка данных для нее реализованы в BitcoinRenderer .



Загрузка готовых данных

Большинство движков и демонстраций WebGL загружают данные из файлов в формате JSON, OBJ или других форматах.

С одной стороны это удобно — можно просто экспортировать модели из Blender или 3ds Max и использовать их в сцене.

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

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

В совокупности эти два недостатка приводят к тому, что зачастую даже простые демо-версии WebGL загружаются и запускаются довольно долго.

В Java-версии нашего фреймворка мы используем двоичные данные, готовые к загрузке непосредственно в буферы OpenGL, а в JS-версии мы применяем тот же подход. XMLHttpRequest уровня 2 поддерживает работу с двоичными данными в JavaScript. Для упрощения работы с XHR2 создан простой класс ДвоичныйЗагрузчикДанных .

Сорт Полная модель обеспечивает работу с сетками.

Метод нагрузка() загружает два буфера для модели — с индексами и данными (координатами вершин, UV-координатами и т. д.).

Эти буферы содержат двоичные данные, готовые к использованию видеокартой.

В классе также есть метод привязкабуферов () , который фактически связывает буферы и должен вызываться непосредственно перед глДравЭлементс() .



Сжатые текстуры в формате ETC1.

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

Наша платформа Java поддерживает форматы ETC1, ETC2, PVRTC и ASTC и использует наиболее подходящие текстуры с учетом возможностей конкретного устройства.

WebGL реализует только текстуры ETC1 и несжатые RGB. В OpenGL ES 2.0 ETC1 является обязательной частью стандарта и поддерживается на всех без исключения устройствах.

Однако в WebGL поддержка сжатия ETC1 не требуется, а наличие расширения необходимо проверять.

WEBGL_compressed_texture_etc1 .

Все настольные браузеры, кроме IE11 и Edge, поддерживают это расширение.

Для браузеров Microsoft необходимо использовать несжатые текстуры.

Проверить, какие форматы текстур поддерживает браузер, можно с помощью эта удобная страница .

Благодаря использованию текстур ETC1 мы используем гораздо меньше памяти, а также смогли ускорить процесс загрузки текстур.

Ведь несжатые текстуры перед попаданием в видеопамять необходимо сначала декодировать из исходного формата (PNG, JPEG, WebP, GIF и т.д.) в растровое изображение (RGBA или RGB, с альфа-каналами или без них) и только потом передавать в драйвер для загрузки в видеокарту.

Текстуры ETC1 не требуют никакой предварительной обработки — они уже готовы к непосредственному использованию видеокартой и поэтому загружаются гораздо быстрее.

Если говорить об экономии памяти, то, например, несжатая RGB-текстура размером 512х512 пикселей занимает 768 Кб, тогда как та же текстура ETC1 занимает всего 128 Кб.

Однако ETC1 не идеален и вызывает некоторые артефакты сжатия.

Эти артефакты практически незаметны на картах диффузии и освещения, но весьма заметны на картах нормалей (искажение в виде блоков пикселей 4х4) и картах отражений (неточная цветопередача).

Поэтому мы используем как сжатые, так и несжатые текстуры в зависимости от требований к качеству.

В Android загрузка текстур ETC1 очень проста — есть стандартная утилита ETC1Util , который выполняет всю работу по загрузке текстуры из файла PKM. В связи с тем, что WebGL не предоставляет никаких средств для загрузки сжатых текстур известных форматов, нам пришлось создать собственный загрузчик текстур ETC1 из файлов формата PKM. PKM — очень простой формат, он состоит из 16-байтового заголовка, за которым следуют двоичные данные, готовые к загрузке в видеокарту.

Более подробную информацию о названии можно найти Здесь И Здесь .

При написании кода получения размеров текстур мы столкнулись с определенным ограничением JavaScript. Эти значения сохраняются как 16-битные целые числа с прямым порядком байтов.

Однако используйте Int16Array получить эти числа не получится, потому что JavaScript не предоставляет возможности указать порядок байтов в буфере, поэтому мне пришлось читать байты, используя Uint8Array и вычислять 16-битные значения вручную из полученных пар младших и старших байтов.



Шейдеры

Приложение использует всего два шейдера: один для поверхности стола, другой для модели монеты.

Табличный шейдер — это простая реализация карт освещения.

Он использует две текстуры: одна карта цветов (диффузная) для задания текстуры дерева, а вторая — карта освещения (lightmap).

Результатом шейдера является просто умножение цветов из этих текстур.

Шейдер монет более сложен, он содержит следующие функции:

  • Карта сферического отражения (так называемое сферическое отображение или маткап)
  • Карта освещения с улучшением цвета
  • Нормальная карта
Карта сферического отражения хранит информацию в изображении, похожем на снимок хромированного шарика:

Портирование Android-приложения на WebGL

По сравнению с другими методами отражения сферическая карта имеет следующие преимущества: + Простой код шейдера и высокая производительность + Использование только одной текстуры + Текстура с отражением легко обрабатывается в графических редакторах, например Photoshop - Плохо работает на плоских поверхностях.

- Некоторое пространство текстуры тратится впустую (углы не используются) Самым большим преимуществом сферической карты является простота ее реализации.

Когда у вас уже есть нормаль, рассчитанная в экранном пространстве, вам просто нужно перенести ее в компонент (x;y), чтобы прочитать текстуру.

Выдержка из кода шейдера:

   

vec4 sphereColor = texture2D(sphereMap, vec2(vNormal2.x, vNormal2.y));

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

А модель монеты состоит в основном из больших плоских поверхностей.

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

При подсветке монет использовался дополнительный трюк.

Для затенения монет использовалась карта освещения.

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

Помимо этого, в темных областях умножаем цвет сам на себя с помощью функции пау() .

Чем темнее карта освещенности, тем выше степень.

Это воспроизводит эффект «захвата» света в ограниченном пространстве и усиления его цвета за счет многократных отражений от металлических поверхностей.

В результате получается более реалистичная металлическая поверхность:

Портирование Android-приложения на WebGL



Результат

Готовое демо можно посмотреть здесь страница .

Все источники доступен на GitHub и вы можете использовать их в своих проектах на условиях лицензии MIT. Теги: #andriod #webgl #шейдеры #GLSL #JavaScript #Разработка для Android #webgl

Вместе с данным постом часто просматривают: