Оптимизируем ассеты для WebGL правильно

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



Геометрия / Меши


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



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



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



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



Карты нормалей


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



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



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



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

  • Ваш объект состоит из множества различных поверхностей.
  • У вас шероховатая поверхность, которая не дает видимых дефектов.
  • Ваши объекты такие отдаленные или маленькие, что пользователь не в состоянии заметить какие-либо артефакты.



Текстурирование


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



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



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



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



Вертексные цвета


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



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



Количество шейдеров


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

Если у вас есть похожие материалы, которые отличаются только текстурами, вы можете использовать только один материал и загружать / менять его текстуры во время выполнения. Для этого вы можете использовать JavaScript или взять визуальный редактор логики, имеющийся в некоторых WebGL-фреймворках. Это не только оптимизирует количество шейдеров, но и уменьшит количество изображений, загружаемых при запуске приложения.



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



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



Draw-вызовы


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

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



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



HDR освещение


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



Тени


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



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



На этом всё. Если у вас есть ещё какие-нибудь советы, которые могут помочь с производительностью WebGL, пишите в комментариях.
  • +16
  • 2,2k
  • 5
Поделиться публикацией

Комментарии 5

    0
    Хороший набор советов.
    P.S. Если можно — как-то пояснить что такое Smooth Group?
    «шейдинг-группы», «с гладкими вертексными группами»
    Это выглядит как интерполяция нормалей, привязанных к вершинам, а в чём смысл разных групп?..
      0
      Спасибо. Smooth Group — это отдельные категории вертексов, в пределах которых нормали интерполируются независимо от других групп. Они позволяют комбинировать плоские и объёмные элементы в одной модели и при этом не увеличивать полигонаж слишком сильно.
        0
        Всё равно непонятно.
        Например кубик с фаской:
        В каждой вершине задана ещё и нормаль к поверхности, поверхность гладкая. На боковых гранях все вершины (минимум 4) имеют одну и ту же нормаль, на фаске — разную. Зачем там целых 4 группы?
        При рендеринге это же всё равно будут треугольники и интерполяция нормалей будет у каждого треугольника своя, независимо от других.

        P.S. Кажись дошло
        В самом WebGL никаких групп нету, эта сущность только в CAD нужна чтобы правильно выставить нормали в вершинах
          0
          В самом WebGL никаких групп нету, эта сущность только в CAD нужна чтобы правильно выставить нормали в вершинах

          Именно так, а в сам движок экспортируются уже готовые нормали.
      0
      Крайне полезная статья, добавил в закладки.

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

      Самое читаемое