Оптимизация сцен для повышения производительности WebGL
В данной статье мы познакомим вас с несколькими методами оптимизации, которые хорошо зарекомендовали себя при создании интерактивных веб-приложений. Эта глава основана на презентации «Софт Эйт Софт» (англ.) на конференции «Вердж3Дей» проходившей в Нидерландах в 2019 году.
- Геометрия и меши
- Карты нормалей
- Текстурирование
- Вертексные цвета
- Количество шейдеров
- Вызовы отрисовки
- HDR-освещение
- Тени
- Смотрите также
Геометрия и меши
В основе 3Д-приложений лежит геометрия, поскольку она формирует основу модели. Чтобы получить более гладкие отражения и ускорить рендеринг, необходимо чтобы сетка была как можно более равномерной, а топология правильной. Вначале следует определиться с уровнем детализации сцены и придерживаться его на протяжении всего процесса моделирования.

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

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

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

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

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

Исходя из нашего опыта, для глянцевых объектов мы рекомендуем использование геометрии middle-poly с группами сглаживания и без карты нормалей.

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

Текстурирование
Вот типичный набор текстур, используемых в создании PBR-материала.

Как вы можете заметить, большинство из них черно-белые. Поэтому вы можете объединять ч/б текстуры в РГБА-каналы одного изображения, до 4 карт на изображение.

Если у вас есть только одна ч/б текстура, вы можете объединить ее с любой существующей РГБ-текстурой, упаковав ее в альфа-канал. Наконец, если у вас нет изображения, с которым данную текстуру можно совместить, вы можете преобразовать ваше ч/б изображение в формат jpeg со сжатием 95% и включенным режимом оттенков серого.

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

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

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

Количество шейдеров
Хорошей практикой является, малое количество различных материалов/шейдеров в вашей сцене. Обработка шейдеров в WebGL приводит к длительной загрузке, что особенно заметно на «Виндоус». Кроме того, если у вас меньше шейдеров, движок будет тратить меньше времени на переключение между ними во время рендеринга, что повышает производительность.
Если у вас есть похожие материалы, которые отличаются только текстурами, вы можете использовать только один материал и загружать/заменять его текстуры во время работы приложения. Для этого можно использовать пазл replace texture или реализовать данный способ с помощью «Ява Скрипт». Это не только оптимизирует количество шейдеров, но и уменьшит количество изображений, загружаемых при запуске приложения.

Вот пример такой оптимизации. Все эти шины представлены только одним материалом и сконфигурированы путем замены его текстур.

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

Вызовы отрисовки
Кроме того, есть еще один важный аспект — количество вызовов отрисовки (draw calls). Это число можно получить из раздела Geometry Buffers вывода информации о производительности. Их число примерно соответствует количеству отдельных объектов, если для каждого объекта назначен только один материал, в то время как для рендеринга объектов из нескольких материалов требуется еще больше вызовов рисования.
Поэтому следует стремиться объединять меши, когда это возможно, и использовать меньше уникальных материалов, чтобы уменьшить количество вызовов отрисовки и улучшить производительность.

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

HDR-освещение
Это помогает значительно улучшить производительность, если вы освещаете сцену только HDR-изображением (.hdr), не используя никаких источников света. Файл HDR может весить менее 1 Мб.

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

Если объект статичен, можно запечь карты теней и окклюзии и применить их к плоскости под объектом.

Смотрите также
Ознакомьтесь с разделом «Поиск проблем с производительностью», чтобы узнать, как обнаружить проблемные места в производительности вашего приложения, и с разделом «Компрессия ассетов», чтобы узнать, как сделать ваши сцены еще более компактными.
Остались вопросы?
Задайте их на нашем форуме!