Android astc что это

Сжатие текстур в Android: сравнение форматов и примеры кода

Назовите самый лучший формат сжатия текстур. Может это PNG, ETC, PVRTC, S3TC, или ещё какой-нибудь? Вопрос непростой, но очень важный. От ответа зависят качество визуального оформления, скорость работы и размеры Android-приложений. Дело осложняется тем, что универсального «самого лучшего формата» попросту не существует. Всё зависит от потребностей разработчика.

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

Предварительные сведения о работе с текстурами и о форматах их хранения

Наложение текстур (texture mapping) – это метод «наклеивания» изображения на поверхности фигур или многоугольников. Для того чтобы было понятнее, фигуру можно сравнить с коробкой, а текстуру – с узорной обёрточной бумагой, в которую эту коробку заворачивают для того, чтобы положить в неё что-нибудь хорошее и кому-нибудь подарить. Поэтому в англоязычной литературе наложение текстур называют ещё и «texture wrapping», что можно перевести как «обёртывание текстурами».


Первый танк – это полигональная модель, а второй – та же модель, на которую наложены текстуры.

MIP-карты (Mipmaps) – это оптимизированные группы изображений, которые генерируются для основной текстуры. Обычно их создают для того, чтобы увеличить скорость рендеринга картинки и для сглаживания изображений (anti-aliasing), то есть – для избавления от эффекта «ступенчатых» линий. Каждый уровень карты (его называют «mip», фактически – это одно из растровых изображений, из них состоит набор текстур, входящих в MIP-карту) – это версия исходной текстуры с пониженным разрешением.

Такое изображение используется в случаях, когда текстурированный объект виден с большого расстояния, или когда его размеры уменьшены. Идея использования MIP-карт строится на том факте, что мы попросту не можем различить мелкие детали объекта, который находится далеко от нас или имеет маленькие размеры. Основываясь на этой идее, различные фрагменты карты можно использовать для представления различных частей текстуры, основываясь на размерах объекта. Это увеличивает скорость рендеринга за счёт того, что уменьшенные варианты основной текстуры имеют намного меньше текселей (пикселей текстуры), то есть GPU приходится обрабатывать меньше данных для вывода текстурированной модели. Кроме того, так как MIP-карты обычно подвергаются сглаживанию, серьёзно уменьшается количество заметных артефактов. Здесь мы рассмотрим MIP-карты в форматах PNG, ETC (KTX), ETC2 (KTX), PVRTC, и S3TC.

Portable Network Graphics (PNG)

PNG – это растровый формат хранения изображения, особенно заметный тем, что в нём используется алгоритм сжатия графических данных без потерь информации. Он поддерживает цветные индексированные изображения (24 бита RGB или 32 бита RGBA), полноцветные и полутоновые изображения, а так же – альфа-канал.

Преимущества

Недостатки

Ericsson Texture Compression (ETC)

Ericsson Texture Compression – это формат сжатия текстур, который оперирует блоками пикселей размером 4×4. Изначально Khronos использовал ETC как стандартный формат для Open GL ES 2.0. (эта версия ещё называется ETC1). В результате этот формат доступен практически на всех Android-устройствах. С выходом OpenGL ES 3.0. в качестве нового стандарта использован формат ETC2 – переработанная версия ETC1. Основное различие между этими двумя стандартами заключается в алгоритме, который оперирует пиксельными группами. Улучшения в алгоритме привели к более высокой точности вывода мелких деталей изображений. Как результат, качество изображений улучшилось, а размер файлов – нет.

ETC1 и ETC2 поддерживают сжатие 24-битных RGB-данных, но они не поддерживают сжатие изображений с альфа-каналом. Кроме того, есть два разных формата файлов, относящихся к алгоритму ETC: это KTX и PKM.

KTX – это стандартный формат файла Khronos Group, он предоставляет контейнер, в котором можно хранить множество изображений. Когда MIP-карта создаётся с использованием KTX, генерируется единственный KTX-файл. Формат PKM-файла гораздо проще, такие файлы, в основном, используют для хранения отдельных изображений. Как результат, при использовании PKM в ходе создания MIP-карты получатся несколько PKM-файлов вместо единственного KTX. Поэтому для хранения MIP-карт использовать формат PKM не рекомендуется.

Преимущества

Недостатки

  • Качество не так высоко, как у PNG (ETC – это формат сжатия изображений с потерями информации).
  • Нет поддержки прозрачности.

Для сжатия изображений в ETC можно использовать Mali GPU Texture Compression Tool и ETC-Pack Tool.

PowerVR Texture Compression (PVRTC)

PowerVR Texture Compression – это формат компрессии графических данных с потерями, с фиксированным уровнем сжатия, который используется, преимущественно, в устройствах Imagination Technology PowerVR MBX, SGX и Rogue. Он применяется в качестве стандартного метода сжатия изображений в iPhone, iPod, iPad.

В отличие от ETC и S3TC, алгоритм PVRTC не работает с фиксированными блоками пикселей. В нём используется билинейное увеличение и смешивание с низкой точностью двух изображений низкого разрешения. В дополнение к уникальному процессу сжатия, PVRTC поддерживает формат RGBA (с прозрачностью) и для варианта 2-bpp (2 бита на пиксель), и для варианта 4-bpp (4 бита на пиксель).

Преимущества

Недостатки

  • Качество не так высоко, как при использовании PNG (PVRTC – это формат сжатия изображений с потерями).
  • PVRTC поддерживается только на аппаратном обеспечении PoverVR.
  • Обеспечивается поддержка квадратных POT-текстур, то есть текстур, ширина и высота которых являются степенью числа 2, хотя в некоторых случаях имеется поддержка прямоугольных текстур.

  • Сжатие текстур в этот формат может быть медленным.

Для сжатия можно использовать PVRTexTool.

S3 Texture Compression (S3TC) или DirectX Texture Compression (DXTC)

S3 Texture Compression – это формат сжатия графических данных с потерями, с фиксированным уровнем сжатия. Его особенности делают этот формат идеальным для сжатия текстур, используемых в 3D-приложениях, рассчитанных на использование графического ускорителя. Интеграция S3TC с Microsoft DirectX 6.0 и OpenGL 1.3 способствовала его широкому распространению. Существует как минимум 5 различных вариантов формата S3TC (от DXT1 до DXT5). Приложение-пример поддерживает чаще всего используемые варианты (DXT1, DXT3 и DXT5).

DXT1 обеспечивает наиболее сильное сжатие. Каждый входной 16-пиксельный блок конвертируется в 64-битный блок, состоящий из двух 16-битных RGB 5:6:5 цветовых значений и 2-х битной таблицы подстановок размером 4×4. Поддержка прозрачности ограничена одним цветом (1-битная прозрачность).

DXT3 конвертирует каждый блок из 16 пикселей в 128 бит, 64 бита приходятся на данные альфа-канала, 64 – на цветовую информацию. DXT3 очень хорошо подходит для изображений или текстур с резкими переходами между прозрачными и непрозрачными областями. Однако если градаций прозрачности нет, а прозрачные участки в изображении имеются, стоит рассмотреть использование DXT1.

DXT5, как и DXT3, конвертирует каждый блок из 16 пикселей в 128 бит, 64 бита приходятся на данные альфа-канала, 64 – на цветовую информацию. Однако, в отличие от DXT3, DXT5 подходит для изображений или текстур с плавными переходами между прозрачными и непрозрачными областями.

Преимущества

Недостатки

  • Качество ниже, чем у PNG (S3TC – это формат сжатия изображений с потерями информации).
  • Поддерживается не на всех Android-устройствах.

Для работы с этим форматом можно пользоваться DirectX Texture Tool из DirectX (включен в DX SDK)

Доступ к данным текстур

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

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

Читайте также:  Kimihane kanojo to kanojo no koi suru ikkagetsu android

Обратите внимание

Заголовок PVRTC упакован с учётом наличия члена данных 64-битного пиксельного формата (mPixelFormat в примере). В коде, скомпилированном для ARM, проводится выравнивание заголовка с добавлением к нему 4 дополнительных байтов, в итоге он, из исходного 52-байтового, становится 56-байтовым. Это приводит к тому, что при выводе на ARM-устройствах изображение искажается. В коде, скомпилированном для процессоров от Intel, подобного не происходит. Упаковка заголовка решает проблему с выравниванием на ARM-устройствах, в итоге текстура отображается правильно как на ARM-устройствах, так и на Intel-устройствах.


Вот как выглядит искажение изображения на ARM-устройстве, вызванное выравниванием заголовка

О приложении-примере

Пример Android Texture Compression, фрагменты которого будут приведены ниже, позволяет всем желающим быстро сравнивать качество текстур пяти форматов. А именно, это Portable Network Graphics (PNG), Ericsson Texture Compression (ETC), Ericsson Texture Compression 2 (ETC2), PowerVR Texture Compression (PVRTC), и S3 Texture Compression (S3TC), который иногда называют DirectX Texture Compression (DXTC).

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

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

Рассматриваемый здесь пример основан на коде, который создал Уильям Гуо (William Guo). Кристиано Феррейра (Christiano Ferreira), специалист по графическим приложениям Intel, дополнил его примером использования сжатия текстур ETC2. Загрузить код можно здесь.


Форматы сжатия текстур: размеры и качество

Загрузка PNG

С MIP-картами в формате PNG можно работать с помощью простой функции glGenerateMipmap из Khronos OpenGL, которая была создана специально для этой цели. Мы, для чтения и загрузки PNG-файлов, воспользовались кодом, подготовленным Шоном Барретом (Sean Barret), stb_image.c, который находится в открытом доступе. Так же этот код используется для нахождения и выборки участка текстуры, который нужно обработать.

Загрузка ETC / ETC2

Как было упомянуто выше, ETC-текстуры могут храниться в файлах формата KTX и PKM. KTX – это стандартный формат сжатия, используемый как контейнер для нескольких изображений, он идеально подходит для создания MIP-карт. В свою очередь, PKM создан для хранения отдельных сжатых изображений, поэтому создание на его основе MIP-карт приводит к необходимости генерировать множество файлов, а это неэффективно. Поддержка MIP-карт для ETC в примере ограничена форматом KTX.

Khronos предоставляет библиотеку с открытым кодом, написанную на C (libktx), в которой поддерживается загрузка MIP-карт из KTX-файлов. Мы этой библиотекой воспользовались и реализовали код в функции LoadTextureETC_KTX, ответственной за загрузку текстур. Функция, которая непосредственно загружает KTX-файлы, называется ktxLoadTextureM. Она позволяет загружать нужную текстуру из данных в памяти. Эта функция – часть библиотеки libktx, документацию по ней можно найти на сайте Khronos.

Вот фрагмент кода, который инициализирует текстуру и предоставляет поддержку MIP-карт для формата ETC (KTX).

Загрузка PVRTC

Поддержка MIP-карт для PVRTC-текстур – задачка чуть посложнее. После чтения заголовка определяется смещение, которое равняется сумме размеров заголовка и метаданных. Метаданные идут следом за заголовком, они не являются частью изображения. Для каждого сгенерированного уровня карты пиксели группируются в блоки (различия зависят от того, применяется ли кодировка 4 бита на пиксель или 2 бита – и тот и другой варианты подходят для PVRTC). Далее, происходит поиск границ, фиксируется ширина и высота блоков. Затем вызывается функция glCompressedTexImage(), она идентифицирует двумерное изображение в сжатом формате PVRTC. Далее, вычисляется размер пиксельных данных и то, что получилось, добавляется к ранее найденному смещению для того, чтобы сгруппировать набор пикселей для следующего фрагмента карты. Этот процесс повторяется до тех пор, пока не будут обработаны все текстуры, из которых состоит карта.

Загрузка S3TC

После загрузки файла, хранящего S3TC-текстуры, определяется его формат и выполняется чтение MIP-карты, расположенной за заголовком. Производится обход фрагмента карты, пиксели группируются в блоки. Затем, для идентификации двумерного изображения в сжатых данных, вызывается функция glCompressedTexImage(). Общий размер блока затем добавляется к смещению для того, чтобы можно было найти начало следующего фрагмента карты и выполнить те же действия. Это повторяется до тех пор, пока не будут обработаны все уровни карты. Вот фрагмент кода, который инициализирует текстуру и предоставляет поддержку MIP-карт для формата S3TC.

Источник

Unity Addressables: памяти хватит всегда

Вы руководите командой из нескольких программистов и художников, работающих над портированием красивой VR-игры на PS4 под Oculus Quest. У вас есть на это шесть месяцев. Каким будет ваш первый ход? Давайте попробуем воспользоваться Unity Addressables.

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

Предположу следующее: примерно 70% читателей скажут, что самой большой проблемой при портировании игры на Quest является производительность ЦП/GPU. Я могу ответить на это: скорее всего, вы правы. Повышение производительности — одна из сложнейших областей в VR-игре. Для оптимизаций такого типа необходимо глубокое изучение продукта, а на это требуется время. Иногда дальнейшая оптимизация невозможна, из-за чего обычно приходится избавляться от затратных элементов геймплея и графики. А разочаровывать игроков опасно.

Скорость, скорость, скорость… Чего же ожидать в этом отношении от платформы Quest? Насколько она производительна? Дело в том, что если вы уже имели опыт разработки на ней, то знаете, что несмотря на её мобильность, она на удивление мощна.

«Да ладно, автор, зачем ты врёшь? Мой телефон начинает тормозить, как только я открываю вторую вкладку браузера. Как ты можешь говорить, что мобильные платформы способны быть производительными?»

Огромная разница заключается в системе активного охлаждения Quest, дающей огромное преимущество для её ЦП/GPU, не обеспечиваемое ни одной другой мобильной платформой. Это мощный вентилятор, сдувающий пыль с ваших волос, и не дающий процессору расплавиться на вашем лице.

Кроме того, более специализированная ОС лучше оптимизирована для рендеринга виртуальной реальности (сюрприз), чем стандартный Android. За последние несколько лет мобильное железо начало быстро догонять стационарные платформы.

Но в то же время не стану отрицать, что задача постоянного рендеринга с частотой 72 fps будет сложной, особенно для портов VR-игр, приходящих с мощных платформ. Когда мы говорим об Oculus Quest, то можете представить себе Snapdragon 835 с экраном, аккумулятором, четырьмя камерами и вентилятором.

То, что выглядит недостатком, можно на самом деле воспринимать как преимущество. Эта мобильная платформа — хорошо исследованное устройство со слабым железом. Можно сказать, что существует тысяча известных трюков для быстрого снижения нагрузки на ЦП и GPU до приемлемого уровня. Если вам это интересно, то можете почитать об этом в моих последующих постах. А в этой статье мы вынесем производительность за скобки.

Привлечь наше внимание в этой проблеме может то, что по сравнению с PS4 у Quest есть одна аппаратная характеристика в два раза меньше: ёмкость ОЗУ. Именно, объём снизился с 8 до 4 ГБ ОЗУ. Это аппроксимация, потому что на обеих платформах операционная система не позволяет использовать их полностью, чтобы можно было отслеживать несколько подсистем, необходимых для работы экосистемы. В Quest можно использовать примерно до 2,2 ГБ ОЗУ; если больше, то уже начинается хаос.

«Но что же ты подразумеваешь под хаосом?» Дело в том, что для игры критически важно реализовать правильное управление памятью. Так получилось, потому что у нас есть два ограничения:

  • Жёсткое ограничение памяти: если превысить определённый порог, то ОС просто убьёт игру
  • Мягкое ограничение памяти

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

Читайте также:  Простейший фоторедактор для андроида

Конечно, гарантированное наличие 2,2 ГБ ОЗУ — это не так много. Обычно это не проблема для новых проектов, в которых статистика постоянно отслеживается с самого начала, но определённо становится затруднением для порта на сильно более слабом железе.

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

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

Не все платформы поддерживают одинаковые параметры импорта: при разработке под разные устройства значительно увеличиваются затраты на конвейер сборки, не говоря уже о сложности QA, графики дизайна и программирования. Например, поддерживает ли это Android-устройство ASTC, или только ETC2 (и вообще что-нибудь из них)? О, и нам ведь ещё нужны 64-битные сборки, но в то же время мы хотим сохранить игроков с 32-битными версиями. Сколько отдельных APK нам нужно создать и протестировать для каждого обновления, выполняемого в игре? Если вы хотите упросить себе жизнь, то не стоит полагаться только на эти техники.

Поэтому нам нужно двинуться глубже. Разумеется, мы хотим, чтобы всё было как можно проще, особенно при создании порта. Переработка игры целиком ради производительности — ещё худший вариант, чем просто её не портировать. В рамках темы статьи я покажу одно из самых важных преимуществ: вы узнаете, как всего за несколько часов уменьшить требуемый объём памяти в два раза.

Разве это не здорово?

Ну давайте, давайте, спросите меня: неужели это действительно возможно в вашем случае? Я отвечу: это зависит от начальных условий, но по моему опыту, ответом будет ДА. Unity Addressables могут оказать здесь огромную услугу. В чём же хитрость? Вам придётся вложить силы и освоить процесс. Но такой рабочий процесс позволит вам завоевать звание сотрудника месяца.

Если вы заинтересовались, то продолжайте чтение.

В этом посте мы пройдём путь от традиционного управления ассетами до системы управления ассетами на основе addressables. Чтобы проиллюстрировать этот процесс, мы портируем упрощённый олдскульный проект в новую эпоху Unity Addressables.

Вы можете задать вопрос: почему бы тебе просто не показать результат на твоей реальной работе?

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

Поэтому вместо этого я предлагаю свою помощь: мы с вами проработаем проект, в котором представлены все сложности, с которым вы столкнётесь завтра в своём следующем проекте. И начнём мы с того, то примем в свою семью рекомендуемых пакетов Unity Addressables.

В этом посте я познакомлю вас с Addressables, чтобы вы могли за считанные минуты реализовать собственную систему Unity Addressables.

Unity Addressables: зачем они нужны?

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

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

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

Насколько это плохо?

Ситуации бывают разные. Если ваша игра скорее всего будет ограничена объёмом памяти? то это очень рискованное решение, потому что игра плохо будет масштабироваться с увеличением количества добавляемых ассетов (например, подумайте о будущих DLC). Если вы выполняете разработку для разнородных устройств, например, для Android, то у вас нет единого объёма памяти; каждое устройство имеет собственную ёмкость, поэтому придётся рассчитывать на наихудший случай. ОС может в любой момент решить убить приложение, если пользователь вдруг переключится, чтобы ответить на сообщение в Facebook. Когда он вернётся, его будет ждать сюрприз — игра уже была закрыта.

Усложняет ситуацию и то, что если позже вы решите (или кто-то решит за вас) портировать игру на другую, менее мощную платформу с сохранением кросс-плея, то вам остаётся только пожелать удачи. Вам точно не захочется столкнуться с такой технической проблемой.

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

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

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

Встречайте Unity Addressables.

Требования к проекту с Unity Addressables

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

  • Руки
  • Умная голова
  • Unity 2019.2.0f1 или выше
  • Проект уровня 1 с GitHub (скачайте zip или через командную строку)
  • Желание покопаться во внутренностях Unity Addressables

Репозиторий git содержит три коммита, по одному на каждый уровень этого поста (если только я чего-то не перепутаю и не создам коммит с исправлением).

Скачайте проект в формате ZIP непосредственно с GitHub

Разработчик уровня 1: традиционное управление ассетами

Мы начнём с простейшего метода управления ассетами. В нашем случае для этого придётся составить список прямых ссылок на материалы скайбокса в компоненте.

Если вы будете делать это со мной, то подготовка займёт три простых шага:

  1. Скачайте проект с git
  2. Откройте проект в Unity
  3. Нажмите кнопку play!

Отлично. Теперь можно понажимать на кнопки, чтобы менять скайбокс. Так оригинально… и скучно. Как я понимаю, пока никаких Unity Addressables.

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

Во-первых, как структурирован наш проект? Он опирается на две основные системы. С одной стороны, у нас есть игровой объект Manager. Этот компонент является основным скриптом, хранящим ссылки на материалы скайбокса и переключающий их в зависимости от событий UI. Всё довольно просто.

Manager предоставляет системе UI функцию для применения к сцене определённого материала благодаря использованию API RenderSettings.

Во-вторых, у нас есть CanvasSkyboxSelector. Этот игровой объект содержит компонент холста, рендерящий набор распределённых по вертикали кнопок. Каждая кнопка при нажатии вызывает вышеупомянутую функцию Manager, заменяющую рендерящийся скайбокс в зависимости от id кнопки. Иными словами, событие OnClick каждой кнопки вызывает функцию SetSkybox объекта Manager. Всё просто, не так ли?

Unity Addressables — иерархия сцены

Теперь настало время приступать к работе. Давайте откроем профилировщик (ctrl/cmd + 7 или Window — Analysis — Profiler). Я буду считать, что вы знакомы с этим инструментом, а значит, знаете, что делать с верхней кнопкой record. После нескольких секунд записи остановите её и посмотрите метрики: CPU, memory и т.п. Есть что-нибудь интересное?

Производительность довольно хороша, и это неудивительно, учитывая масштаб проекта. Можно просто превратить этот проект в VR-игру и я гарантирую, что никого из игроков не стошнит, как это часто бывает в Eve: Valkyrie.

В нашем случае мы сосредоточимся на разделе памяти. В простом режиме просмотра вы увидите примерно такую картину:

Управление ассетами уровня 1 — простое профилирование памяти

Читайте также:  Терапия андроид последняя версия

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

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

Настало время магии. Переключим профилировщик памяти в подробный режим. Смотрите!

Управление ассетами уровня 1 — подробное профилирование памяти

Чёрт возьми, что здесь произошло? Все текстуры скайбокса загружены в память, но одновременно отображается только одна из них. Видите, что у нас получилось? Эта сырая архитектура занимает целых 400 МБ.

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

  • Традиционное управление ассетами подразумевает прямые ссылки
  • Поэтому все объекты загружены постоянно
  • Проект при этом плохо масштабируется

Разработчик уровня 2: процесс работы с Unity Addressables

В играх мы начинаем с уровня 1, и это нас устраивает, но как только мы разберёмся с правилами геймплея, настаёт время покинуть безопасные городские стены и повышать свой уровень. Именно этому посвящён данный раздел.

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

Позвольте мне вам помочь. Возьмём лопату, чтобы прорыть туннель для побега из тюрьмы традиционного управления ассетами. Давайте добавим в наш набор новый интересный инструмент: API Unity Addressables.

Первое, что нам надо сделать — установить пакет Addressables. Для этого перейдём в Window → Package Manager:

Unity Package Manager — Unity Addressables

После установки нам нужно пометить материалы как addressables. Выберем их и активируем флаг addressables в окне инспектора.

Управление ассетами уровня 2 (Unity Addressables)

Таким образом мы вежливо просим Unity включить эти материалы и их текстурные зависимости в базу данных addressables. Эта база данных будет использоваться во время выполнения сборок для упаковки ассетов в блоки (chunks), которые можно легко загружать в любой момент игры.

Сейчас я покажу вам кое-что крутое. Откройте Window → Asset Management → Addressables. Догадываетесь, что это? Эта наша база данных, которой не терпится ожить!

Управление ассетами уровня 2 (Unity Addressables) — главное окно

Дорогой читатель, это была лёгкая часть. А теперь начинается интересная.

Я хочу, чтобы вы посетили нашего старого друга из предыдущего раздела: сэра Manager. Если его проверить, то мы обнаружим, что он по-прежнему хранит прямые ссылки на ассеты! Нам этого не нужно.

Вместо этого мы научим менеджер использовать косвенные ссылки, т.е. AssetReference (в Unreal Engine они называются мягкими ссылками — soft references).

Давайте сделаем наш компонент красивее:

Здесь происходит следующее:

  • Серьёзное изменение происходит в строке 7, где мы храним список косвенных ссылок (AssetReference) вместо прямых ссылок на материалы. Это изменение является ключевым, потому что эти материалы НЕ будут загружаться автоматически только когда на них ссылаются. Их загрузку необходимо будет выполнять явным образом. Затем изменим значение поля в редакторе.
  • Строка 13: поскольку теперь мы выполняем асинхронный рабочий процесс, лучше использовать корутину. Мы просто запустим новую корутину, которая будет заниматься изменением материала скайбокса
  • В строках 18-20 мы проверяем, есть ли у нас существующий дескриптор материала скайбокса, и если есть, то мы освобождаем скайбокс, который рендерили ранее. Каждый раз, когда мы выполняем такую операцию загрузки при помощи API Addressables, мы получаем дескриптор, который нужно хранить для будущих операций. Дескриптор — это просто структура данных, содержащая данные, относящиеся к управлению определённым addressable-ассетом.
  • Мы преобразуем ссылку на конкретный addressable в материал скайбокса в строке 23, а затем вызываем его функцию LoadAssetAsync, над которой можно выполнить операцию yield (строка 25), чтобы перед продолжением работы программы мы могли дождаться завершения этой операции. Благодаря использованию дженериков нет необходимости в использовании неприятных преобразований типов. Отлично!
  • Наконец, после того, как материал и его зависимости загрузятся, мы начинаем менять скайбокс сцены в строке 26. Материал будет передан в поле Result, которое принадлежит дескриптору, использованному для его загрузки.

Управление ассетами уровня 2 (Unity Addressables) — список AssetReference

Помните: этот код не готов к продакшену. Не используйте его при программировании самолёта. Я решил, что ради простоты стоит пожертвовать надёжностью.

Но хватит объяснений. Пора увидеть его в действии.

Пожалуйста, выполните следующие шаги:

  1. В окне addressables приготовьте контент (build player content)
  2. Затем выполните сборку для выбранной платформы
  3. Запустите её и подключите к ней профилировщик (памяти).
  4. Не уроните челюсть от удивления.

Уровень 2 (Unity Addressables) — Build Player Content

Управление памятью уровня 2 (Unity Addressables) — профилировщик памяти

Разве приготовленные ассеты не вкусны?

Мне нравится, когда профилировщик доволен. А сейчас мы видим самый счастливый профилировщик в мире. А довольный профилировщик означает следующее: во-первых, больше довольных игроков, которые смогут поиграть в вашу игру хоть на Nokia 3210. Во-вторых, это довольные продюсеры. А для вас это означает, что будет доволен ваш кошелёк.

В этом и состоит мощь системы Addressables.

Но Addressables накладывают небольшие дополнительные трудозатраты. С одной стороны, программистам нужно обеспечить поддержку асинхронных рабочих процессов (это легко реализуется при помощи корутин). Кроме того, дизайнерам придётся изучать возможности системы, например, addressable groups, и набраться опыта для принятия осознанных решений. И, наконец, IT-отдел очень обрадуется тому, что придётся настраивать инфраструктуру для передачи ассетов по сети, если вы предпочтёте хостить их онлайн.

Должен вас поздравить. Объясню, чего мы добились:

  • Правильное управление памятью.
  • Ускорение первоначальной загрузки.
  • Ускоренное время установки, уменьшение размера приложения в магазине.
  • Повышенная совместимость с устройствами.
  • Асинхронная архитектура.
  • Открыли дверь для хранения этого контента онлайн → то есть к отделению данных от кода.

Я бы гордился таким достижениями. Это хорошая отдача от наших вложений труда.

О, и не забудьте упомянуть про опыт работы с Addressables на собеседовании.

Вспомогательные материалы: создание инстансов и подсчёт ссылок. Информацию по этой теме можно прочитать в моём посте.

Дополнительно: альтернативные стратегии загрузки. Прочитать о них можно в моём посте.

  • Управление ассетами на основе Addressables замечательно масштабируется.
  • Addressables добавляют асинхронное поведение
  • Не забывайте подготавливать контент при изменениях, иначе игра будет иметь розоватый оттенок!

Управление ассетами уровня 3 (??) — сетевая доставка контента

Управление ассетами уровня 3 (??) — сетевая доставка контента

В предыдущем разделе мы совершили самый важный прорыв. Повысили свои навыки, перейдя от традиционной системы управления ассетами к рабочему процессу на основе addressables. Это огромная победа для проекта, потому что благодаря небольшим затратам времени мы обеспечили пространство для масштабирования объёма ассетов, сохраняя при этом низкий уровень потребления памяти. Это достижение на самом деле повысило вас до уровня 2, поздравляю! Однако нам предстоит ответить на ещё один вопрос:

Нет. Мы едва коснулись темы Addressables, существуют и другие способы улучшения проекта благодаря этому мощному пакету.

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

Из него вы узнаете о следующих аспектах:

  • Окно Addressables: важные подробности
  • Профилирование Addressables: не позвольте утечкам памяти испортить вам жизнь
  • Сетевая доставка: снижение времени с начала установки до игрового процесса
  • Интеграция в конвейер сборок
  • Практические стратегии: ускорение рабочего процесса, избавляющие от необходимости десятиминутных кофе-брейков

И, что ещё более важно, мы ответим на следующие вопросы:

  • В чём заключается скрытый смысл Send Profiler Events?
  • Насколько полезен API AddressableAssetSettings?
  • Как интегрировать всё это с API BuildPlayerWindow?
  • В чём разница между Virtual Mode и Packed Mode?

Руководство по уровню 3 можно прочитать в моём посте.

Источник

Оцените статью