Портування Android-додатки на WebGL

Ідея портування Android-додатки на WebGL
Зараз WebGL підтримується практично будь-яким пристроєм і працює досить стабільно і швидко навіть на мобільних пристроях, тому було дуже цікаво спробувати реалізувати що-небудь на цій технології. У нас вже є великий досвід роботи з OpenGL ES 2.0 в Android — створили досить багато різних тривимірних живих шпалер.


Ці програми ми створювали без використання готових сторонніх движків (наприклад, Unity) або високорівневих фреймворків для роботи з OpenGL (таких як libGDX). Зважаючи на те, що код не обтяжений обмеженнями сторонніх фреймворків, програми виходять дуже маленькими, і швидкими, а також ми маємо можливість повністю оптимізувати рендеринг під потреби кожного додатка.

WebGL заснований на OpenGL ES 2.0, а тому процес портування шпалер досить простий і прямолінійний.

Фреймворк візуалізації
Також як і в оригінальному коді Java, реалізовані базові класи BaseRenderer BaseShader. Було вирішено використовувати класи ECMAScript 2015 так як ця нотація спрощує читаність коду, а єдиний браузер, який не підтримує JS класи це IE11. BaseRenderer містить код для створення WebGL контексту, ініціалізації, відстеження зміни розміру вікна, і т. П. Також у ньому є порожні «заглушки» для рендерінгу сцени. BaseShader містить код для компіляції та використання шейдерів. Собсвенно сам рендеринг сцени і завантаження даних для неї реалізовані BitcoinRenderer.

Завантаження готових даних
Більшість WebGL движків і демок завантажують дані з файлів в JSON, OBJ, або інших форматах. З одного боку, це зручно — досить просто експортувати моделі з Blender або 3ds Max і використовувати їх на сцені. Однак з іншого боку, цей підхід вимагає додаткової обробки вихідних даних на клієнта для створення буферів з даними, готовими для використання відеокартою. Також дані в цих форматах часто містять багато надлишкової інформації, яка не використовується, але все одно займає більшу частину вихідного файлу, що істотно збільшує обсяг переданих даних. Разом ці два недоліки призводять до того, що часто навіть простенькі WebGL демки вантажаться і запускаються досить довго.

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

Клас FullModel забезпечує роботу з мешами. Метод load() завантажує два буфера для моделі з індексами і даними (координати вертексов, UV-координати тощо). Ці буфери містять двійкові дані, готові для використання відеокартою. Також клас має метод bindBuffers(), який власне прив'язує буфери і його треба викликати безпосередньо перед glDrawElements().

Стислі текстури в форматі 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-бітних big-endian цілих чисел. Однак використовувати Int16Array для отримання цих чисел не вийде, так як JavaScript не надає способу задавати порядок байт буфера, і довелося читати байти використовуючи Uint8Array і обчислювати 16-бітні значення вручну з отриманих пар молодших і старших байт.

Шейдери
У програмі використовується всього два шейдера: один для поверхні столу, а інший для моделі монет.

Шейдер для столу — це проста реалізація lightmap-ів. Він використовує дві текстури: одна карта кольору (diffuse) для завдання текстури дерева, а друга — карта освітленості (lightmap). Результат роботи шейдерів — це просто перемножування квітів з цих текстур.

Шейдер монет більш складний, він містить в собі наступні функції:

  • Сферичаская карта відбиттів (т. зв. sphere mapping або matcap)
  • Карта освітлення (lightmap) з підсиленням кольору
  • Карта нормалей (normal map)
Сферична карта відбиттів зберігає інформацію в картинці, яка виглядає як знімок хромованого кулі:



У порівнянні з іншими техніками відображення, сферична карта має наступні переваги:

+ Простий код шейдерів та висока продуктивність
+ Використання тільки однієї текстури
+ Текстура з відображенням проста в обробці графічних редакторах, наприклад Photoshop
— Погано працює на рівних поверхнях
— Частина текстурного простору витрачається впусту (кути не використовуються)

Найбільша перевага сферичної карти — це простота реалізації. Коли у вас вже є нормаль розрахована в просторі екрана, вам достатньо взяти її (x;y) компоненту для читання текстури. Витяг з коду шейдера:

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

Звідси ж випливає і найбільший недолік даної техніки: так як в розрахунках бере участь тільки екранна нормаль, то великі рівні полігони будуть заповнені одним і тим же кольором (так як будуть мати однакову нормаль по всій поверхні). А модель монети якраз і складається в основному з великих плоских поверхонь. Для боротьби з цим недоліком ми додали карту нормалей і зробили її як можна більш різноманітної: додали шуму, написів, цифр і т. д. Цей прийом позбавляє модель рівних поверхонь і сферичні відображення працюють ідеально.

При освітленні монет був використаний додатковий трюк. Для затінення монет використана карта освітлення (lightmap). Однак, просте множення кольору на карту освітлення дає хоч і більш-менш коректний, але нудний результат: затемнені місця стають просто темніше. На додаток до цього, у темних місцях ми множимо колір на самого себе, використовуючи функцію pow(). Ступінь тим вище, чим темніше карта освітленості. Це відтворює ефект того як світло потрапляє в «пастку» в замкнутому просторі і посилює свій колір через багаторазового відбиття від металевих поверхонь. В результаті отримуємо більш реалістичну металеву поверхню:


Результат
Готову демку можна переглянути на цій сторінки. Всі вихідні коди доступні на GitHub, ви можете використовувати їх у своїх проектах на умовах ліцензії MIT.
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.