Vvmebel.com

Новости с мира ПК
1 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Как оптимизировать игру на юнити

Как оптимизировать игру на юнити

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

Какова стоимость графики

Графическая часть вашей игры нагружает в первую очередь две системы компьютера: GPU (графический процессор) и CPU (центральный процессор). Первое правило любой оптимизации: найти, где возникает проблема , так как стратегия оптимизации для GPU и CPU имеет существенные различия (иногда даже возникает ситуация, когда при оптимизации для GPU больше нагрузки ложится на CPU и наоборот).

Типичные узкие места и их проверка:

  • GPU часто ограничен филлрейтом (fillrate) или пропускной способностью памяти.
  • Запуск игры с более низким разрешением экрана увеличивает производительность? Тогда вы скорее всего ограничены филлрейтом GPU.
  • CPU часто ограничен количеством вещей, которые должны быть отрисованы, также известно, как “ draw calls ”.
  • Проверьте показателль “draw calls” в окне Rendering Statistics; если он составляет больше нескольких тысяч (для PC) или нескольких сотен (для мобильных устройств), то вам может потребоваться оптимизация количества объектов.

Конечно, это только эмпирически выведенные закономерности; узкие места могут быть и на других участках. Менее типичные узкие места:

  • Рендеринг не создаёт проблем ни для GPU, ни для CPU. Проблема может быть, к примеру, в скриптах или физике. Используйтепрофайлер для поиска источника проблемы.
  • GPU обрабатывает слишком много вершин. Какое количество вершин является нормальным, определяется GPU и набором вертексных шейдеров. Можно посоветовать использовать не более 100 тысяч для мобильных устройств и не более нескольких миллионов для PC.
  • CPU обрабатывает слишком много вершин. Некоторые процессы предполагают обработку вершин CPU: skinned meshes, симуляция ткани, частицы и т.п.

Оптимизация для CPU — количество draw call (в дальнейшем, DC)

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

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

Чтобы снизить нагрузку на CPU, старайтесь уменьшить количество видимых объектов:

  • Объединяйте близко расположенные объекты: вручную или используя инструмент draw call batching в Unity.
  • Используйте меньше материалов, объединяйте текстуры в большие текстурные атласы.
  • Используйте меньше объектов, которые должны визуализироваться несколько раз (отражения, тени, попиксельные источники света и т. п., смотрите ниже).

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

Однако, когда вы используете много пиксельных источников света при Forward rendering path, бывают ситуации, в которых не имеет смысла объединять объекты, это более подробно описано ниже.

GPU: Оптимизация геометрии моделей

При оптимизации геометрии модели есть два основных правила:

  • Не используйте треугольников больше, чем необходимо
  • Старайтесь держать количество швов на UV-карте и количество жёстких рёбер (удваивающих вершины) как можно более низким

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

В то время как количество геометрии в моделях оказывает влияние в первую очередь на GPU, некоторые функции Unity предполагают обработку моделей и на CPU, например mesh skinning.

Производительность освещения

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

  • Это намного быстрее работает (в 2–3 раза по сравнению с 2 пиксельными источниками света)
  • Это выглядит лучше, так как вы можете запечь глобальное освещение и с более высоким качеством

Во многих случаях можно заменить размещение источников света правильной настройков шейдеров и контента. Для примера, вместо размещения источника света прямо перед камерой для получения эффекта “подсветка краёв модели” (rim lighting), проще добавить расчёт этого эффекта прямо в шейдере.

Освещение в forward rendering

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

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

В процессе визуализации Unity находит все источники света вокруг меша и рассчитывает их важность для данного меша. В настройках Quality Settings можно задать, сколько источников света в конце концов может использоваться для освещения каждого меша. Для каждого источника света его приоритет вычисляется на основании расстояния до меша и яркости этого источника света. Также имеет значение параметр Render Mode внутри компонента Light, который может принимать два значения: Important или Not Important . Источники света, помеченные как Not Important имеют более низкий приоритет.

Для примера рассмотрим игру, где игрок управляет автомобилем, движущимся в темноте со включёнными фарами. Скорее всего, передние фары будут наиболее важным источником света в игре и параметр Render Mode будет установлен для них в значение Important . Задние огни будут менее важны, не оказывая значительного влияния на конечное изображения, так что для них Render Mode можно установить в Not Important , сэкономив тем самым аппаратные ресурсы.

Оптимизация пиксельного освещения сохраняет ресурсы и CPU и GPU: CPU делает меньше draw calls, а GPU обрабатывает меньше вершин и растеризует меньше пикселей для каждого дополнительного объекта.

GPU: сжатие текстур и мипмапы

Использование сжатых текстур уменьшает размер ваших текстур (в результате они быстрее загружаются и занимают меньше памяти), а также может значительно повысить производительность. Сжатые текстуры используют малую часть пропускной способности памяти, в сравнении с 32-битными RGBA-текстурами.

Использование мипмап для текстур

Как правило, параметр импорта Generate Mip Maps включён для текстур, используемых в 3D-сцене. В этом случае сжатие текстур поможет ограничить количество текстурных данных, транспортируемых в GPU при визуализации. Мимпапы позволяют GPU использовать для маленьких треугольников текстуры пониженного разрешения.

Есть исключение из этого правила: когда один тексель (пиксель текстуры) соответствует одному пикселю экрана, что встречается в элементах пользовательского интерфейса и в 2D-играх.

LOD и послойное задание дистанции для сulling

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

Это может быть достигнуто использованием системы Level Of Detail или ручной настройкой дистанции обрезки для камеры по слоям. Вы можете поместить мелкие объекты в отдельный слой и задать ему дистанцию обрезки, используя свойствоCamera.layerCullDistances.

Тени в реальном времени

Тени в реальном времени хорошо выглядят, но они могут сильно снижать производительность, одновременно добавляя дополнительные draw calls для CPU и дополнительную обработку для GPU. Подробности даны на странице Shadows.

GPU: советы для написания высокопроизводительных шейдеров

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

Имейте в виду, что производительность GPU на мобильных устройствах и PC начального уровня скорее всего будет намного ниже, чем на PC, который вы используете для разработки. Как правило, шейдеры нужно вручную оптимизировать, чтобы уменьшить количество расчётов и чтений текстуры для получения высокой производительности. Для примера, некоторые встроенные в Unity шейдеры имеют “мобильные” эквиваленты, которые работают намного быстрее за счёт некоторых ограничений и упрощений.

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

Сложные математические операции

Трансцендентные математические функции ( pow , exp , log , cos , sin , tan , т. п.) являются весьма дорогими, так что рекомендуется использовать не более одной такой операции на пиксель. Рассмотрите возможность использования подстановки текстуры в качестве альтернативы, где это возможно.

Не рекомендуется пытаться написать собственные операции: normalize , dot , inversesqrt . При использовании встроенных операций драйвер скорее всего сгенерирует более совершенный код, чем вы.

Помните, что альфа-тест сделает ваши фрагменты ( медленнее ).

Операции с плавающей точкой

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

Если шейдер написан на Cg/HLSL, то точность определяется следующим образом:

  • float — полный 32-битный формат с плавающей точкой, подходит для вертексных трансформаций, но очень медленный.
  • half — уменьшенный 16-битный формат с плавающей точкой, подходит для текстурных координат, и приблизительно вдвое быстрее чем float .
  • fixed — 10 битный формат с фиксированной точкой подходит для цветов, рассчета освещения и других высоко производительных операций. Он работает примерно в 4 раза быстрее, чем float .
Читать еще:  Как посмотреть марку видеокарты

В шейдере, написанном на GLSL ES точность значения с плавающей точкой указывается в highp , mediump , lowp в указанном порядке.

Подробности о производительности шейдеров можно прочитать на странице Shader Performance.

Как оптимизировать игру на юнити

Здравствуйте! У меня вопрос по поводу оптимизации игры.
Как это делается в играх где мир состоит из кубов (или просто очень много объектов) ?
Ведь в играх где кубы, это отдельные кубы, ведь каждый можно разрушить, но лагов то нету. А там на камере видно очень много кубов!

Я построил здание из кубов, раскопировал его по сцене. Получилось около 60 к кубов видимых на камере! Но ведь это даже совсем не детализированные здания. При этом на i5 3570 и gtx 770 выдаёт всего то 7 фпс. Как убираются лаги? И почему лагов в других играх нету? Например ace of spades. У меня это просто объекты. А как это делается в других играх и за счёт чего лаги полностью отсутствуют даже на слабых системах ?

Добавлено (21.10.2013, 00:20)
———————————————
И это очень маленькая локация, в игре планируются локации намного большего масштаба. Только проблема с производительностью..

robertono,
9 миллионов полигонов? ОМГ
Один куб это 6 полигона, 900000 полигонов разделить на 6 у тебя в сцене это должно быть 1500000 кубов должно быть, их там нет, логично посмотреть там нет такого количества.
Возьми куб и посмотри на его сетку и выложи сюда, сколько в одном кубе полигонов.

Майнкрафт на планшетах грузится.

400 DC, 70-80 FPS

850 DC 35-40 FPS

1,3K DC 20-25 FPS

Добавлено (21.10.2013, 10:31)
———————————————
Не обратил внимания, оказывается динамический батчинг уже используется. Заостри внимание на материалах. Чтобы на одном кубе был один материал

Спасибо огромное за ответы конечно.. но всё же
Моя проблема в том что я не сказал что кубы можно будет ломать

Нету смысла создавать куб без всех 6 полигонов, т.к. этот куб можно будет сломать , и если полигонов не будет то это будет уже не куб..

Да, потому что там наверняка это делается совсем по другому. Я могу выложить префаб в котором будет все 6 зданий и вы сами всё у себя попробуете.

Это куб созданный в юнити. GameObject — Create — Cube

На каждом кубе один и тот же difuse материал который ставится когда создаёшь куб в юнити.

Я про физику ничего не говорил

+5 фпс только. Того 14.

Дело не в том, есть ли тени, какие материалы, есть ли оклюжн кулинг, сколько полигонов на кубе юнити.
В этой кубической игре отсутствуют чанки. В этой игре куб, это отдельно созданный gameobject cube без материала. Каждый куб.
Возможно мне нужно просто посмотреть MinePackage.
Я в первом сообщении не просто так упомянул

.
Просто в других играх это делается совсем по другому как я понял.

Вы видите характеристики моего компьютера? Выигрыш 5 фпс от теней, от полигонов безсмыссленый , так как игра сильно тормозит на видео карте Geforce GTX 770 !

Добавлено (21.10.2013, 16:19)
———————————————
Вот вам префаб одного здания, врубите юнити, поставьте first person controller, поставьте здание на сцену 6 раз (у меня стоит 6 зданий) и посмотрите сколько фпс будет у вас. Не думаю что больше 2.

Добавлено (21.10.2013, 16:29)
———————————————
Открыл я значит MinePackage, текстуры у меня грузится не хотели , но я включил максимальное сглаживание (x8), fantastic, врубил тени.

насколько смог разобраться, в MinePackage используется вычисление лицевых сторон, батч процессор, который рассовывает все вычисления по отдельным потокам, и декоратор, который накладывает текстуру на видимый полигон используя признаки «пиксола» (тоже в отдельном потоке).
там вообще нет кубов!
мир хранится в координатах и признаках (позиция, текстура, UV развертка). каждый chunk хранит в себе и меш, и меш рендер, и меш фильтр, но они включаются только для видимых блоков, наверное только в зоне досягаемости рейкаста плейера.
грубо говоря — после декорирования это просто литой «пиксольный» (вортексный) объект, который просто выглядит как куча блоков.
когда ломаешь «пиксол» — то декоратор вычисляет новое видимое поле, только для сопряженных с измененным chunk’ом и все. мы снова имеем единый вортексный объект.
если сделаешь в 3D max такой «террайн» слитый с деревьями, удалив все скрытые полигоны, и запекши текстуры — то он вот так и будет работать в unity. у меня 68 fps / 1M вертексов / 513K триугольников в FullHD на весь мир.

KamiRonin, из твоего выше сказанного, для себя я могу выбрать создание системы вычисления лицевых сторон. Это должно очень сильно поднять производительность (я думаю). А где можно прочитать про батч процессор?

А вот хотелось бы поговорить о чанках — нужны ли они мне? Если я в какой то момент захочу добавить кубам (во время игры, любой куб который я выберу) rigidbody, то получается чанки тогда безсмысслено делать? И если я хочу построить небоскрёб, сделать ему красивое падение и разрушение то чанки тоже уже не годятся?

Occlusion Culling своими руками.
Можно сделать? Точнее вопрос можно ли выглядит тупо, потому что написать можно что угодно. Скорее вопрос «как».
Я видел такую крутую штуку, Field Of View с помощью теней.
http://unitycoder.com/upload/demos/FOVShadowcasting1/
Может можно как то тени обрабатывать но не обрабатывать ? Т.е. как бы просчитывать их но не выводить на экран?
И например куда лучи солнца попадают, всмысле на какие объекты , те и рендерить. Источник света повесить на камеру или игрока. Но что бы тоже света небыло, теней небыло но они обрабатывались (очень сомневаюсь что реально, но может можно сделать как то очень похоже). Так можно было бы не рендерить то что находится например ЗА каким нибудь кубом и совсем не видно!

Добавлено (21.10.2013, 22:52)
———————————————
KamiRonin, Какие вообще есть способы что бы не рендерить объекты которые не видно но они например находятся за какими то объектами спереди?

Добавлено (21.10.2013, 23:00)
———————————————
KamiRonin, А мне кажется всё равно пришлось бы писать свою оклюжн кулинг систему, т.к. которая в про версии она же как запекает объекты, а значит если они динамические то это уже не получится использовать!

Добавлено (21.10.2013, 23:21)
———————————————
KamiRonin, Из чего вообще состоят эти системы? Сетка из триггеров?

Добавлено (22.10.2013, 00:04)
———————————————
Вот такое нехитрое решение я нашёл для oclusion culling!
http://unitycoder.com/blog/2012/02/15/raycast-realtime-visibility-2-0/
разработчик предлагает пускать до 60 к рейкастов! Но я проверил, и для плавности достаточно 1024, но не 512) И того,пускаем тысячу рейкастов и отрубаем то что его не трогает) Можно делать массив то что включено, и удалять от туда когда не видно. Вообщем придумать можно хорошо я думаю

Методы оптимизации при разработке в Unity 3D

  • Рассказы о своих проектах, 8 марта 2013 в 16:24
  • Саша

Евгений Семушин, руководитель компании по разработке программного обеспечения EcmaSoft

Производительность имеет решающее значение для мобильных игр. Особенно если игра сочетает в себе физику, AI (искусственный интеллект) и полностью анимированных персонажей 3D-мира. Некоторое время назад мы сделали игру под названием «Spearfishing 3D — подводная охота» для iOS. За первые полгода после релиза игра была скачана около двух миллионов раз и попала в топ-10 в категории «Игры» в разных странах мира. Одна из основных проблем, которую нам понадобилось решить, — обеспечение работы игры с 60 fps. Это стало проще с выпуском iPad и iPhone 4, но мы по-прежнему должны поддерживать как минимум 30 fps для iPhone 3G/3GS. В этой статье я опишу подходы, которые мы использовали для оптимизации игр на основе Unity.

Использование Performance Profiler

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

Чтобы использовать профайлер на мобильных устройствах, сделайте билд в Developer mode. Из документации Unity:

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

Здесь также можно отметить флажок для автоматического соединения редактора и плеера. Профайлер показывает график использования CPU во время игры. Просто подключите мобильное устройство к машине для разработки и проходите игру. Профайлер покажет все проблемы в режиме реального времени. Он разбивает активности на Rendering, Scripts, Physics, GarbageCollector, VSync и другие. В мобильных играх часто бывают проблемы с рендерингом. Иногда скачки производительности возникают в скриптах при загрузке сцены, но в этом нет ничего необычного. Некоторые скачки связаны с физикой.

Физика и искусственный интеллект

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

  • Старайтесь, чтобы как можно меньше объектов двигалось одновременно. «Спящие» объекты намного дешевле.
  • То же самое касается искусственного интеллекта. Если объект находится далеко от главного героя или его не видно, не запускайте скрипты искусственного интеллекта.
  • Рейкасты очень дорогие. Не делайте рейкаст на каждый фрейм — попробуйте кэшировать результаты и пропустить некоторые фреймы.
  • Старайтесь избегать сложных меш коллайдеров.
  • Проверьте функции Update() . Они запускают каждый кадр и, следовательно, дорогие. Вместо этого используйте Coroutines .

Static batching

Это фича Unity, которая экономит много циклов CPU. Каждый раз, когда объект рендерится, происходит Draw Call — команда для CPU или GPU о том, что объект должен отрендериться. Unity запускает несколько вызовов отрисовки и накладывает их друг на друга, это и формирует сцену. Однако каждый Draw Call требует ресурсов CPU, поэтому мы хотим минимизировать их количество.

Тут и стоит использовать Batching. Он нужен для того, чтобы не делать лишние Draw Calls. Batching бывает двух видов: статический и динамический. Статический дает лучшую производительность, поэтому мы всегда стараемся использовать его.

Ивент переехал в онлайн, есть новые даты ( 14 – 15 июля ) , Москва и онлайн, 10 750–138 000 ₽

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

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

Dynamic Batching

Для не статических объектов можно использовать Dynamic Batching. Объекты с Dynamic Batching требуют определенные ресурсы на каждую вершину, поэтому он применяется только к мешам, содержащим менее 900 вершин. Наш шейдер использует Vertex Position, UV и Colors. Таким образом, у нас может быть до 300 вершин на объект.

Некоторые полезные советы из руководства Unity:

  • Динамический батчинг связан с дополнительной нагрузкой для каждой вершины, так что он применим только к мешам, в сумме содержащим менее 900 вершин.
  • Если ваш шейдер использует Vertex Position, Normal и единственный UV, то вы можете батчить до 300 вершин; тогда как если шейдер использует Vertex Position, Normal, UV0, UV1 и Tangent, то только 180 вершин.
  • Не масштабируйте. Объекты с масштабом (1,1,1) и (2,2,2) не будут батчиться.
  • Равномерно масштабированные объекты не будут батчиться с неравномерно масштабированными.
  • Использование различных материалов приведет к сбою батчинга.
  • Объекты с Lightmap имеют дополнительный (скрытый) параметр материала: смещение/масштаб в Lightmap, поэтому объекты с Lightmap не будут батчиться.

Заметьте: если у объекта есть анимация, но при этом есть часть, которая никогда не двигается, можно отметить эту часть как статическую, и она не будет мешать анимации.

Как оптимизировать игру на юнити

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

Какова стоимость графики

Графическая часть вашей игры нагружает в первую очередь две системы компьютера: GPU (графический процессор) и CPU (центральный процессор). Первое правило любой оптимизации: найти, где возникает проблема , так как стратегия оптимизации для GPU и CPU имеет существенные различия (иногда даже возникает ситуация, когда при оптимизации для GPU больше нагрузки ложится на CPU и наоборот).

Типичные узкие места и их проверка:

  • GPU часто ограничен филлрейтом (fillrate) или пропускной способностью памяти.
  • Запуск игры с более низким разрешением экрана увеличивает производительность? Тогда вы скорее всего ограничены филлрейтом GPU.
  • CPU часто ограничен количеством вещей, которые должны быть отрисованы, также известно, как “ draw calls ”.
  • Проверьте показателль “draw calls” в окне Rendering Statistics; если он составляет больше нескольких тысяч (для PC) или нескольких сотен (для мобильных устройств), то вам может потребоваться оптимизация количества объектов.

Конечно, это только эмпирически выведенные закономерности; узкие места могут быть и на других участках. Менее типичные узкие места:

  • Рендеринг не создаёт проблем ни для GPU, ни для CPU. Проблема может быть, к примеру, в скриптах или физике. Используйтепрофайлер для поиска источника проблемы.
  • GPU обрабатывает слишком много вершин. Какое количество вершин является нормальным, определяется GPU и набором вертексных шейдеров. Можно посоветовать использовать не более 100 тысяч для мобильных устройств и не более нескольких миллионов для PC.
  • CPU обрабатывает слишком много вершин. Некоторые процессы предполагают обработку вершин CPU: skinned meshes, симуляция ткани, частицы и т.п.

Оптимизация для CPU — количество draw call (в дальнейшем, DC)

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

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

Чтобы снизить нагрузку на CPU, старайтесь уменьшить количество видимых объектов:

  • Объединяйте близко расположенные объекты: вручную или используя инструмент draw call batching в Unity.
  • Используйте меньше материалов, объединяйте текстуры в большие текстурные атласы.
  • Используйте меньше объектов, которые должны визуализироваться несколько раз (отражения, тени, попиксельные источники света и т. п., смотрите ниже).

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

Однако, когда вы используете много пиксельных источников света при Forward rendering path, бывают ситуации, в которых не имеет смысла объединять объекты, это более подробно описано ниже.

GPU: Оптимизация геометрии моделей

При оптимизации геометрии модели есть два основных правила:

  • Не используйте треугольников больше, чем необходимо
  • Старайтесь держать количество швов на UV-карте и количество жёстких рёбер (удваивающих вершины) как можно более низким

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

В то время как количество геометрии в моделях оказывает влияние в первую очередь на GPU, некоторые функции Unity предполагают обработку моделей и на CPU, например mesh skinning.

Производительность освещения

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

  • Это намного быстрее работает (в 2–3 раза по сравнению с 2 пиксельными источниками света)
  • Это выглядит лучше, так как вы можете запечь глобальное освещение и с более высоким качеством

Во многих случаях можно заменить размещение источников света правильной настройков шейдеров и контента. Для примера, вместо размещения источника света прямо перед камерой для получения эффекта “подсветка краёв модели” (rim lighting), проще добавить расчёт этого эффекта прямо в шейдере.

Освещение в forward rendering

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

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

В процессе визуализации Unity находит все источники света вокруг меша и рассчитывает их важность для данного меша. В настройках Quality Settings можно задать, сколько источников света в конце концов может использоваться для освещения каждого меша. Для каждого источника света его приоритет вычисляется на основании расстояния до меша и яркости этого источника света. Также имеет значение параметр Render Mode внутри компонента Light, который может принимать два значения: Important или Not Important . Источники света, помеченные как Not Important имеют более низкий приоритет.

Для примера рассмотрим игру, где игрок управляет автомобилем, движущимся в темноте со включёнными фарами. Скорее всего, передние фары будут наиболее важным источником света в игре и параметр Render Mode будет установлен для них в значение Important . Задние огни будут менее важны, не оказывая значительного влияния на конечное изображения, так что для них Render Mode можно установить в Not Important , сэкономив тем самым аппаратные ресурсы.

Оптимизация пиксельного освещения сохраняет ресурсы и CPU и GPU: CPU делает меньше draw calls, а GPU обрабатывает меньше вершин и растеризует меньше пикселей для каждого дополнительного объекта.

GPU: сжатие текстур и мипмапы

Использование сжатых текстур уменьшает размер ваших текстур (в результате они быстрее загружаются и занимают меньше памяти), а также может значительно повысить производительность. Сжатые текстуры используют малую часть пропускной способности памяти, в сравнении с 32-битными RGBA-текстурами.

Использование мипмап для текстур

Как правило, параметр импорта Generate Mip Maps включён для текстур, используемых в 3D-сцене. В этом случае сжатие текстур поможет ограничить количество текстурных данных, транспортируемых в GPU при визуализации. Мимпапы позволяют GPU использовать для маленьких треугольников текстуры пониженного разрешения.

Есть исключение из этого правила: когда один тексель (пиксель текстуры) соответствует одному пикселю экрана, что встречается в элементах пользовательского интерфейса и в 2D-играх.

LOD и послойное задание дистанции для сulling

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

Это может быть достигнуто использованием системы Level Of Detail или ручной настройкой дистанции обрезки для камеры по слоям. Вы можете поместить мелкие объекты в отдельный слой и задать ему дистанцию обрезки, используя свойствоCamera.layerCullDistances.

Тени в реальном времени

Тени в реальном времени хорошо выглядят, но они могут сильно снижать производительность, одновременно добавляя дополнительные draw calls для CPU и дополнительную обработку для GPU. Подробности даны на странице Shadows.

GPU: советы для написания высокопроизводительных шейдеров

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

Имейте в виду, что производительность GPU на мобильных устройствах и PC начального уровня скорее всего будет намного ниже, чем на PC, который вы используете для разработки. Как правило, шейдеры нужно вручную оптимизировать, чтобы уменьшить количество расчётов и чтений текстуры для получения высокой производительности. Для примера, некоторые встроенные в Unity шейдеры имеют “мобильные” эквиваленты, которые работают намного быстрее за счёт некоторых ограничений и упрощений.

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

Сложные математические операции

Трансцендентные математические функции ( pow , exp , log , cos , sin , tan , т. п.) являются весьма дорогими, так что рекомендуется использовать не более одной такой операции на пиксель. Рассмотрите возможность использования подстановки текстуры в качестве альтернативы, где это возможно.

Не рекомендуется пытаться написать собственные операции: normalize , dot , inversesqrt . При использовании встроенных операций драйвер скорее всего сгенерирует более совершенный код, чем вы.

Помните, что альфа-тест сделает ваши фрагменты ( медленнее ).

Операции с плавающей точкой

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

Если шейдер написан на Cg/HLSL, то точность определяется следующим образом:

  • float — полный 32-битный формат с плавающей точкой, подходит для вертексных трансформаций, но очень медленный.
  • half — уменьшенный 16-битный формат с плавающей точкой, подходит для текстурных координат, и приблизительно вдвое быстрее чем float .
  • fixed — 10 битный формат с фиксированной точкой подходит для цветов, рассчета освещения и других высоко производительных операций. Он работает примерно в 4 раза быстрее, чем float .

В шейдере, написанном на GLSL ES точность значения с плавающей точкой указывается в highp , mediump , lowp в указанном порядке.

Подробности о производительности шейдеров можно прочитать на странице Shader Performance.

Как оптимизировать игру на юнити

При разработке игры ,можно столкнуться с проблемой оптимизации, когда даже при относительно не большом количестве полигонов и без использования каких либо эффектов, игра притормаживает даже на топовых устройствах. Это может быть из-за того, что в сцене много мелких объектов и они в разы увеличивают Draw Calls, с этой проблемой можно справиться путем объединения всех объектов с одним материалом в один Mesh, через встроенную в Unity функцию, которая находится по следующему пути: Component/Mesh/Combine Children, подробнее о ней будет чуть ниже.

В общем ниже будут перечислены основные приемы оптимизации игр в Unity.

Несколько советов по снижению Draw Calls (Draw Calls — количество обращений CPU к GPU)

1. Использовать как можно меньше текстур и материалов. Желательно, чтобы как можно больше объектов использовало один и тот же материал. Один и тот же материал может быть использован на объектах двумя способами: через renderer.material и renderer.sharedMaterial. В первом случае получается независимая копия материала, свойства которой можно менять без изменения тех же свойств на остальных объектах. Батчится же будут только меши, на которые наложены материалы через sharedMaterial. Материал, который вешается через редактор, по умолчанию вешается именно на sharedMaterial.
Но тут есть одно но — в каждом меше должно быть Mesh -> Combine Children.

Правильное использование музыки в игре:

1. Если фоновая музыка одна, то вполне уместно не упаковывать трек в памяти и читать его после старта сцены.
Фоновую музыку исключительно стримить с ресурсов и исключительно в MP3 (мало занимает места, хорошо стримится). Короткие звуки можно перегнать в ogg для уменьшения времени распаковки и распаковывать в памяти, либо стримить с ресурсов — по обстоятельствам. Так же необходимо понимать, что не все источники будут слышны одновременно на мобилках так, как они слышны в редакторе. На части устройств (смарты) при количестве AudioSource > 4 появлялся визг с хрипом, а так же ощутимые лаги, на части прекрасно работало (планшеты). Для себя принял решение держаться в рамках максимум 4-ех проигрываемых звуков. WAV — не использовать никогда.

1. Использовать только 1 источник света для освещения, затемнения отдельных частей карты лучше использовать Lightmap`ы
2. Старайтесь как можно реже, или вообще не использовать объекты с Rigidbody
3. Fog — дает сильную нагрузку
4. Шейдеры для материалов, стараться использовать из категории Mobile/. — более оптимизированы

1. Использовать небольшие размеры террейна

150×150
2. Pixel Error — выставить с 0 до максимального значения ( хоть это и предаст прыгающие вершины при приближении камеры, зато в разы увеличит производительность)
3. Отключать флажок Draw
4. Не использовать отрисовку травы в инструментах Terrain`a — в разы уменьшает производительность

1. Все расчеты производить исключительно в Update. В FixedUpdate можно делать небольшие проверки, специфичные для физики, но лучше вообще избегать использования FixedUpdate. Почему? Update вызывается FPS-равное количество раз и увеличение нагрузки просто будет просаживать скорость рендеринга рывками. Это не страшно, т.к. все апдейты должны вестись с учетом Time.deltaTime. FixedUpdate выполняется равное количество раз в секунду и движок ждет завершения выполнения. В результате игру будет визуально дергать при неравномерной вычислительной нагрузке в FixedUpdate.
2. Не использовать new (типа new Vectro3(x,y,z), new Rect()) в циклах и часто вызываемых местах
3. CompareTag более чем вдвое быстрее прямой проверки тэга по имени.
4. (thisTransform.position — target.position).sqrMagnitude быстрее Vector3.Distance
5. Делайте как можно меньше вызовов thisTransform.forward или position, лучше эти значения один раз получить в Update, и использовать во всем скрипте.. Это касается любых готовых свойств MonoBehaviour, включая сам transform. Ощущение, что они всегда получаются выбором из списка компонентов, без кеширования — его нужно делать руками. Все вектора в глобальном пространстве (forward, right, up и т.п.) всегда перевычисляются при каждом обращении к ним по иерархии GameObject — надо прочитать один раз и использовать в текущем коде.
6. Для включение скрипта на объекте при возможности использовать не GetComponent(. ).enabled с заранее отключенным скриптом, а AddComponent(. )
при заранее не повешенном скрипте на объекте

7. Использование Статических переменных

При использовании JavaScript наиболее важной оптимизацией является использование статических типов вместо динамических. Unity использует метод, который называется type inference, для автоматической конвертации переменных JavaScript к статическому коду, для этого вам ничего не понадобиться делать.

В приведенном выше примере foo автоматически распознается как переменная типа integer. Таким образом Unity может применить множество оптимизаций времени компиляции, без затратных динамических поисков имени переменной и тд. Это одна из причин, почему Unity JavaScript в среднем в 20 раз быстрее чем какие либо другие реализации JavaScript.

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

Рассмотрим несколько примеров:

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

Здесь foo у нас имеет определённый тип. Производительность в данном случае будет гораздо лучше.

8. Используйте #pragma strict

Конечно, сейчас проблема состоит в том, что вы обычно не замечаете использование динамической вёрстки. #pragma strict сможет вам помочь. Просто добавьте в начало кода #pragma strict и Unity отключит динамическую вёрстку в данном скрипте, вынуждая вас использовать статическую. Там где тип будет неизвестен, Unity сообщит нам про ошибки компиляции. В этом случае foo будет выдавать ошибку на этапе компиляции:

9. Кешированый поиск компонентов

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

Всякий раз когда вы получаете доступ к компоненту через GetComponent или средством доступа переменной, Unity должен найти нужный компонент из игрового объекта. Время на поиск можно легко сократить если использовать кеширование ссылки на компонент в часной (private) переменной.

Просто преобразуйте этот код:

Последний вариант будет работать намного быстрее, так как Unity не нужно искать компонент Transform в игровом объекте каждый кадр.
Тоже самое применимо для скриптовых компонентов, где вы используете GetComponent вместо transform или других изменений свойств.

10. Используйте встроенные массивы

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

11. Не делайте вызов функции, если без этого можно обойтись

Самый простейший и лучший способ оптимизации – это совершать как можно меньше лишней работы. К примеру, когда враг далеко от нас, наилучшим будет сделать так, чтобы он «заснул». То есть не совершал никаких действий пока игрок не подойдёт ближе. Вот медленный вариант реализации этого случая:

Это не самая удачная идея, так как Unity должен вызывать update функцию постоянно, а значит мы выполняем лишнюю работу каждый кадр. Наилучшим решением в данном случае будет отключение программы врага, пока игрок не подойдёт поближе. Существует 3 способа реализации этой идеи:

1) Использовать OnBecameVisible и OnBecameInvisible. Эти вызовы заложены в системе прорисовки. Как только какая-нибудь камера видит объект, вызывается OnBecameVisible, когда ни одна камера не видит его, делается вызов OnBecameInvisible. В некоторых случаях это оправдано, но иногда это проблематично для AI, так как враги становятся неактивными, когда вы отклоняете от них камеру.

2) Используйте триггеры. Простой шарообразный триггер области может творить чудеса. При выходе из выбранной нами области влияния мы получаем вызовы OnTriggerEnter/Exit.

3) Используйте Coroutines. Главным недостатком Update является то, что он исполняется каждый кадр. Вполне возможным была бы проверка расстояния до игрока каждые 5 секунд. Это бы неплохо повысило производительность.

Ссылка на основную публикацию
Adblock
detector