Оптимизация 3D-графики под WebGL (опыт PLANT-SIM)

    В этой статье речь пойдет об оптимизации Unity-сцены проекта Plantsim 1.0.: о визуальной части цифровой копии предприятия Tennessee Eastman Process, реализованного на Unity 2017.1.1f1.


    image


    Заметка от партнера IT-центра МАИ и организатора магистерской программы “VR/AR & AI” — компании PHYGITALISM.


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


    Платформа Unity Команда Зачем
    PlantSim 1.0 PC на базе: Intel i7 Nvidia GTX 1070ti 2017.3.0f3 Default Pipeline Несколько 3D художников Энтузиазм моделить и творить красоту
    PlantSim 2.0 Ноутбук: Intel i5 Nvidia 1050ti Google Chrome 2019.2.15f1 LWPR Один 3D художник Ещё больше энтузиазма победить страшную задачу

    Таблица сравнения разработки проектов


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


    image
    Пайплайн разработки PlantSim 2.0


    Анализ предстоящей работы


    WebGL — это работа 3D графики с использованием возможностей браузеров Google Chrome, Mozilla, Safari. Первостепенными задачами для нас являлись оптимизация, сохранение того же уровня реализма и поддержание работоспособности приложения на 30FPS+. Для этого нам предстояло работать в пайплайне мобильной разработки.


    image
    Unity: WebGL Build


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


    Красивой визуализации в WebGL добиться можно, но сложно. Имеется ряд особенностей, о которых желательно знать, если вы собираетесь сделать подобный проект самостоятельно и/или работаете с 3D графикой впервые.


    Перед тем, как начать непосредственно работу над 3D, мы выстроили четкий план со списком моделей, которые необходимо оптимизировать.


    image
    Таблица с планом оптимизации для отслеживания хода работы


    Вот краткий список моделей, что присутствовали в сцене раньше:


    • OutPutTank — 2 шт
    • Reactor — 1 шт, модель была раздельная
    • ReactorExplosion — 1 шт, отдельная анимации разлета уничтоженного реактора
    • Condenser — 1 шт
    • Separator — 1 шт
    • PipesSystem — различная система труб на сцене
    • Stripper — 1 шт
    • Valve — 6 шт
    • Tank — 4 шт
    • Refrigerator — 1 шт
    • Compressor — 3 шт
      В PlantSim 1.0 на сцене было 189 736 трисов, и главной задачей для нас была оптимизация модели на 60%. Таким образом мы получим 75 895 треугольников, что будет удовлетворять нашему полигональному бюджету.
      image
      График расчета суммарного предполагаемого количества полигонов после оптимизации

    Оптимизация меша


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


    image
    Модель Reactor (PlantSim 1.0) — анализ иерархии и сетки


    • Нелогичные наименования объектов
    • Много отдельных элементов
    • Сложная топология

    Сам Reactor имел 21998 треугольников. По плану нам было необходимо избавиться от всего лишнего и малозначительного, и получить 8800 треугольников. Перед тем, как начать оптимизировать, мы проанализировали объекты вновь и заметили новую важную деталь: модели OutPutTank, Reactor и Striper имели одни и те же элементы — основание и лестницу. Это означало, что эти элементы можно дублировать и использовать для них один материал.


    В итоге, после работы над Reactor объектом (это первый объект, с которого началась оптимизация), мы получили новую модель в 7258 треугольников. Напомню, что по плану было 8000. При условии, что теперь UV карта одна, объект представляет собой объединенный меш и один материал — стало ясно, что задачу мы сможем реализовать, а итоговая сумма треугольников окажется намного меньше, чем планировали изначально.


    image
    Модель Reactor (PlantSim 2.0) —оптимизированная иерархия и сетка


    • Исправили наименования объектов
    • Уменьшили количество отдельных элементов
    • Упростили и оптимизировали топологию

    Объект ReactorExplosion имел сложную анимацию взрыва, красивую и эффектную — разлет маленьких кусков реактора с сохранением только его основания. После первой полной сборки сцены наш FPS сильно проседал непосредственно на моменте взрыва, который помимо этой анимации меша так же имел и анимацию, состоящую из 1000 частиц инструмента Particle System. Появился вопрос, что создавало трудности для отрисовки: анимация или частицы? Мы обсудили задачу с Unity разработчиком и выявили, что оба фактора слишком тяжелые для WebGL движка, поэтому было решено оптимизировать эффект взрыва, используя 5 частиц (это возможно благодаря FlipBook текстурам). Со стороны разработки так же была необходима оптимизация анимации внутри Unity.


    FlipBook — это покадровая анимация, вложенная в одну текстуру. Соответственно, чем больше кадров, тем больше разрешение самой текстуры и ее вес. Этот способ отрисовки анимации наиболее оптимальный, так как вместо огромного количества частиц и сложных симуляций мы обходимся одной или несколькими частицами, в которых за один цикл проигрывается наш взрыв. Таким образом, используя всего 5 частиц, был оптимизирован эффект с исходными 1000.


    С анимацией было сложнее, так как каждый осколок Reactor был индивидуальным и имел свою запеченную анимацию — это и тянуло WebGL вниз по FPS. Со стороны Unity разработки было предложено запечь всю анимацию в один объект, а метод отрисовки с Mesh renderer переключить на Skinned mesh renderer. Таким образом вместо одновременного перемещения тысячи transform points у нас была цепочка костей и один transform points (Origin самого объекта). Как итог, FPS вырос с 3–5 во время воспроизведения эффекта до 15–20 во время запуска анимации, благо этот фриз сохранялся лишь 0,5 секунды. Кстати, ReactorExplosion объект имел 41220 треугольников, и в угоду экономии времени, которого было мало, было решено не создавать новую анимацию с нуля, а использовать старую, оптимизируя описанным способом.


    В итоге работа по оптимизации меша закончилась успешно. Выше мы упоминали, что на сцене располагалось 189736 треугольников (если не учитывать ReactorExplosion, то 148516 треугольников). Отнимая 60% всей геометрии, мы хотим получить на выходе 59403 треугольника (после оптимизации). У нас получилось 61064 треугольника, что превысило наши планы по оптимизации, но все равно было намного ниже полигонального бюджета, выставленного в самом начале проекта. С учетом ReactorExplosion было 102284 треугольника, что так же было около границы обозначенного бюджета.


    Задача выполнена, переходим к текстурированию.


    image
    График расчета суммарного фактического количества полигонов после оптимизации


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


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


    • Base Color/Albedo — RGBA изображение, определяющее, какой цвет у поверхностей. Иногда идет с Alpha каналом прозрачности поверхностей.
    • Ambient Occlusion — Ч/Б изображение с информацией затенений объекта.
    • Metallness — Ч/Б изображение, определяющее металлическую природу поверхности.
    • Smoothness — Ч/Б изображение, определяющее степень размытости поверхности или ее мелких отдельных деталей.
    • Normal Map — RGB изображение, симулирующее светотень от мелких неровностей поверхности.
    • Height Map — Ч/Б изображение, отвечающее за степень искажения неровностей поверхности. Часто используется в связке с Normal Map.
    • Emission — RGB изображение, отвечающее за самосвечение отдельных участков или всей поверхности объекта. Может влиять на Global Illumination параметры, то есть участвовать в освещении других объектов в сцене.
      image
      Набор текстур для модели Striper из проекта PlantSim 2.0

    Благодаря текстурным картам имитируются поверхности на моделях. После анализа списка можно заметить сходства — помимо RGB текстур мы имеем много черно-белых карт. Что же это значит для оптимизации?


    Дело в том, что отдельно R G и B, а также A каналы и представляют собой черно-белый слой. А значит отдельно в одну текстуру RGBа можно зашифровать сразу четыре текстуры. Как это работает:


    image
    Комбинирование четырех ч/б текстурных карт в одну текстуру


    Далее эту Combine texture расшифровывают и отдают в отдельные каналы материала в Unity.
    Также хотелось бы упомянуть Normal Map. Эта текстура — мощный инструмент для оптимизации модели, с помощью нее возможно избавиться от мелкой детализации модели и впоследствии отобразить при рендеринге на сцене.


    image
    Сравнение двух моделей Compressor


    На этом примере наглядно видна разница поверхностей старой модели и новой, оптимизированной. Данную текстуру создают двумя способами:


    1. Отрисовка вручную в специальных программах, например Substance Painter, используя подготовленные кисти неровностей.
    2. Запекание неровностей с HighPoly модели (с повышенной детализацией, фасками, неровностями и углублениями) на LowPoly модель, которая максимально оптимизирована. Данную процедуру используют как в Substance Painter, так и в Blender инструментах.

    Материалы и шейдеры


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


    image
    Набор материалов на различных объектах. Один цвет — один материал


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


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


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


    Запекание света


    Давайте поговорим о том, как работает свет в Unity, а именно о типе освещения Global Illumination. Это “честный” способ отображения отражения света от поверхности объекта и создания теней. В Unity тени строятся по двум типам объектов — Dynamic и Static объекты.


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


    В случае статичных объектов подразумевается, что они находятся в покое, а тени всегда сохраняют свое положение. Как раз для таких объектов можно запечь тень объекта на пространство в специальный Lightmap текстуры. Учитывая задачу оптимизации и отказ от Realtime просчета теней, это наиболее оптимальный подход.
    image
    Представление сцены без Lightmap текстурной карты и после ее создания
    В PlantSim 2.0 мы запекали тени от всех объектов, если они не участвовали в анимациях.


    Хитрости в работе с WebGL


    К финалу разработки мы стали сражаться за количество FPS уже в собранных билдах, отслеживая напрямую в Google Chrome. Сохранялась проблема — почему FPS на ноутбуке c i7 процессором и GTX 1070ti не повышается больше 30, а наоборот, иногда даже проседает. Ведь не может быть так, что всей проделанной работы было недостаточно.


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


    image
    Таблица стресс-тестов на различных устройствах. Скриншоты фиксируют одинаковую ситуацию и количество FPS в данный момент.


    В тестировании участвовали как мощные ноутбуки на базе Windows и Apple MacBook PRO, так и слабые ноутбуки, на которых не предполагалась работа с 3D графикой. Для чистоты тестирования мы так же использовали стационарный компьютер с RTX 2080ti (кстати, на нем FPS был стабильно 60). FPS оказался разным у всех устройств.


    Разгадка оказалась куда проще, чем предполагалось изначально. Дело в том, что работу браузера Google Chrome определяет некоторые факторы:


    1. Подключен ли ноутбук к зарядке? Если нет, то вероятно, что мощность видеокарты значительно снижена из за экономии аккумулятора.
    2. Есть ли на ноутбуке интегрированная видеокарта (видеокарта, которая встроена в центральный процессор или материнскую плату)?

    Проверить первый пункт достаточно легко, второй — уже сложнее. Мы попробовали дать конкретную задачу для приложения Google Chrome, сделать запуск с параметрами повышенной мощности, однако результатов это не давало. Видеокарты фирмы NVIDIA имеют отдельное приложение по управлению ресурсами видеокарты на устройстве — NVIDIA control panel. В этом приложении мы нашли Google Chrome и вручную выставили работу с помощью дискретной видеокарты, а не интегрированной.


    image
    Окно Nvidia Control Panel — настройки производительности для отдельного приложения


    В итоге, после очередного тестирования билда на Google Chrome, счетчик FPS победно показывал 70–90 — это означало, что во всех предыдущих тестированиях в отрисовке 3D графики браузера участвовала куда более слабая видеокарта (интегрированная), из-за стараний ноутбука сэкономить заряд батареи.


    Вывод


    Разработка проекта такого рода специфична, но во многом интересна, так как WebGL — это новое направление работы с 3D графикой и представление ее в WEB.


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


    Полезные ссылки:


    IT-центр МАИ
    Компания
    Реклама
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее

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

      0
      Все описанные методы выше не новые, но важные и влияют на скорость загрузки приложения, и насколько будет комфортно пользователю просматривать в браузере.
      Сколько ни говори «халва», во рту слаще не станет. Статье на тему WebGL хотя бы одна ссылка на интерактивную 3D модель просто необходима, скриншоты её не заменят.
      Спасибо за почти отличную статью по актуальной теме, успехов в дальнейшей оптимизации и продвижении WebGL в массы.
        +2
        Спасибо за замечание! Добавили в текст две ссылки:
        Пример WebGL проекта с отрисовкой фотореалестичной воды.
        Примеры WebGL библиотеки three.js.

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

        В качестве наиболее употребимово примера использования технологии WebGL можно рассматривать отображении моделей в Sketchfab.

        Отображение gltf моделей в web доступно всем для использования с помощью gLTF Viewer, а для того чтобы просто начать самому встраивать графику в Web можно посмотреть примеры здесь.
          0
          Вот и ладушки. Коммерческий и не нужно, каустика и физика — то что доктор прописал.
            0
            Не подскажете, что и где покрутить, чтобы эти примеры нормально рисовались в Firefox 81.0 на Linux (Ubuntu)?
            В Chromium всё супер!
              0
              В Windows всё нормально…
                +1
                Любопытно.
                Загуглил ошибку из отладчика «Uncaught Error: WebGL not supported», поиск поэтапно привёл сюда (через get.webgl.org, который подтвердил проблему).
                По рекомендации, отключил Use hardware acceleration when available, перезапустил браузер — заработало!
                Потом включил обратно, ещё раз перезапустил — по-прежнему работает, мистика…
        • НЛО прилетело и опубликовало эту надпись здесь
            +2
            При чем тут WebGL если у вас Юнити? Вы оптимизировали проект в Юнити под Веб-версию Юнити и только.
            Юнити не имеет никакого отношениея к настоящему WebGL, в Unity свой WebGL со своими правилами.
            Что вы имеете в виду? Пять лет разрабатываю на Unity и впервые слышу, что WebGL там какой-то не такой.

            WebGL — это же API браузера, как он может зависеть от того используется Unity или нет?
            0
            Написал свой WebGL движок. Объект с 250 тыс. треугольников прорисовывает в среднем за 1 миллисекунду на стареньком компьютере. Нужно будет еще немного оптимизировать код для повышения скорости. Движок называется «Silver Rain». В интернете его нет. Можете не искать.
              0
              На дискетах распространяется?

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

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