Оптимизация Производительности Навигации
Распространенные проблемы производительности, связанные с Навигацией, можно разделить на следующие категории:
Проблемы производительности при анализе узлов дерева сцены для запекания навигационной сетки.
Проблемы с производительностью при запекании реальной навигационной сетки.
Проблемы производительности при запросах пути NavigationAgent.
Проблемы с производительностью при реальном поиске пути.
Проблемы с производительностью синхронизации навигационной карты.
В следующих разделах вы найдете информацию о том, как выявить и устранить или, по крайней мере, уменьшить их влияние на частоту кадров.
Проблемы производительности при анализе узлов дерева сцены
Совет
Отдавайте предпочтение простым формам с минимальным количеством граней, например, не используйте округлые формы вроде круга, сферы или тора (torus).
В качестве исходной геометрии отдавайте предпочтение использованию физических форм столкновений, а не сложных визуальных сеток, поскольку сетки необходимо копировать из графического процессора, и они, как правило, гораздо более подробны, чем необходимо.
В целом, избегайте использования очень сложной геометрии в качестве исходной для запекания навигационных сеток. Например, никогда не используйте очень детализированную визуальную сетку, так как преобразование её формы в массивы данных и вокселизация для запекания навигационной сетки займёт много времени, не давая существенного прироста качества финальной навигационной сетки. Вместо этого используйте очень упрощённую версию формы. Ещё лучше использовать очень примитивные формы, такие как блоки и прямоугольники, которые лишь приблизительно охватывают ту же геометрию, но при этом дают достаточно хороший результат запекания для поиска пути.
Предпочитайте использовать простые формы коллизий физики вместо визуальных мешей в качестве исходной геометрии для запекания навигационных мешей. Физические формы коллизий по умолчанию являются очень ограниченными и оптимизированными формами, которые легко и быстро разбираются. Визуальный меш, с другой стороны, может варьироваться от простых до сложных. Более того, чтобы получить доступ к данным визуального меша, парсеру необходимо запрашивать массивы данных меша у RenderingServer, поскольку данные визуального меша хранятся непосредственно на GPU и не кэшируются на CPU. Это требует блокировки потоков RenderingServer, что может существенно повлиять на частоту кадров во время выполнения, в то время как рендеринг выполняется в многопоточном режиме. Если рендеринг выполняется в однопоточном режиме, влияние на частоту кадров может быть еще более значительным, и разбор меша может "заморозить" всю игру на несколько секунд при работе со сложными мешами.
Проблемы с производительностью при запекании навигационной сетки
Совет
Во время выполнения всегда предпочитайте использовать фоновый поток для запекания навигационных сеток.
Увеличьте NavigationMesh cell_size и cell_height, чтобы создать меньше вокселей.
Измените SamplePartitionType с водораздела на монотонный или слои, чтобы повысить производительность выпечки.
Предупреждение
НИКОГДА не масштабируйте исходную геометрию с узлами, чтобы избежать ошибок точности. В большинстве случаев масштаб применяется только визуально, и формы, которые очень велики в своём базовом масштабе, всё равно требуют значительной дополнительной обработки даже при уменьшении масштаба.
Запекание навигационных сеток во время выполнения всегда следует по возможности выполнять в фоновом потоке. Даже для небольших навигационных сеток запекание может занять гораздо больше времени, чем можно уместить в один кадр, по крайней мере, если частота кадров должна оставаться на приемлемом уровне.
Сложность исходных данных геометрии, проанализированных из узлов дерева сцены, оказывает большое влияние на производительность запекания, поскольку все должно быть отображено на сетку / воксели. Для производительности запекания во время выполнения размер и высота ячеек NavigationMesh должны быть установлены как можно выше, не вызывая проблем с качеством navigation mesh для игры. Если размер или высота ячеек слишком низкие, запекание вынуждено создавать чрезмерное количество вокселей для обработки исходной геометрии. Если исходная геометрия охватывает очень большой игровой мир, то возможно даже, что процесс запекания исчерпает память в середине и приведет к сбою игры. Тип раздела также может быть понижен в зависимости от сложности исходной геометрии игры, чтобы повысить производительность. Например, игры с преимущественно плоскими поверхностями с блочной геометрией могут обойтись монотонным или слоистым режимом, которые намного быстрее запекаются (например, потому что они не требуют прохода поля расстояний).
Никогда не масштабируйте исходную геометрию с помощью узлов. Это может привести не только к множеству ошибок точности из-за неправильного сопоставления вершин и рёбер, но и к тому, что некоторые масштабы проявляются только визуально, а не в фактически проанализированных данных. Например, если масштаб сетки визуально уменьшен в редакторе, например, установлен на 0,001 для MeshInstance, для запекания сетки всё равно потребуется гигантская и очень сложная сетка вокселей.
Проблемы производительности при запросах пути NavigationAgent
Совет
Избегайте ненужных сбросов пути и запросов в каждом кадре в скриптах NavigationAgent.
Избегайте обновления всех путей NavigationAgent в одном кадре.
Логические ошибки и неэффективные операции в пользовательских скриптах NavigationAgent часто приводят к проблемам с производительностью. Например, обратите внимание на сброс пути в каждом кадре. По умолчанию NavigationAgent оптимизированы для запроса новых путей только при изменении целевой позиции, изменении навигационной карты или при слишком большом отклонении от желаемого пути.
Например, когда ИИ должен двигаться к игроку, целевая позиция не должна устанавливаться на основе позиции игрока в каждом кадре, так как это приводит к запросу нового пути в каждом кадре. Вместо этого следует сравнивать расстояние от текущей целевой позиции до позиции игрока, и только когда игрок отошёл слишком далеко, следует устанавливать новую целевую позицию.
Не проверяйте заранее, достижима ли целевая позиция в каждом кадре. То, что выглядит как невинная проверка, на самом деле эквивалентно дорогостоящему запросу пути в фоновом режиме. Если планируется запросить новый путь в любом случае, если позиция достижима, путь следует запрашивать напрямую. Проверка последней позиции возвращаемого пути и того, находится ли она на "достижимом" расстоянии от проверяемой позиции, позволяет ответить на вопрос "достижима ли эта позиция?". Это позволяет избежать выполнения двух полных запросов пути в каждом кадре для одного и того же NavigationAgent.
Разделите общее количество NavigationAgents на группы обновлений или используйте случайные таймеры, чтобы они не все запрашивали новые пути в одном кадре.
Проблемы с производительностью при реальном поиске пути
Совет
Оптимизируйте чрезмерно подробные навигационные сетки, уменьшив количество полигонов и ребер.
Стоимость фактического поиска пути напрямую коррелирует с количеством полигонов и рёбер навигационной сетки, а не с реальным размером игрового мира. Если в гигантском игровом мире используются высокооптимизированные навигационные сетки с небольшим количеством полигонов, покрывающих большие площади, производительность должна быть приемлемой. Если игровой мир разбит на очень маленькие навигационные сетки, каждая из которых состоит из крошечных полигонов (например, в случае с TileMaps), производительность поиска пути снизится.
Распространенной проблемой является внезапное падение производительности, когда целевая позиция не может быть достигнута в запросе пути. Такое падение производительности является "нормальным" и является результатом слишком большой и неоптимизированной навигационной сетки с большим количеством полигонов и рёбер для поиска. При обычном поиске пути, когда целевая позиция может быть достигнута быстро, поиск пути выполняет ранний выход сразу после её достижения, что может на некоторое время скрыть этот недостаток оптимизации. Если целевая позиция не может быть достигнута, поиск пути должен выполнить гораздо более длительный поиск по доступным полигонам, чтобы убедиться, что позиция абсолютно недостижима.
Проблемы с производительностью синхронизации навигационных карт
Совет
По возможности объединяйте полигоны навигационных сеток по вершинам, а не по ребрам.
При внесении изменений, например, в навигационные сетки или навигационные регионы, NavigationServer должен синхронизировать навигационную карту. В зависимости от сложности навигационных сеток, это может занять значительное время и повлиять на частоту кадров.
NavigationServer объединяет навигационные сетки либо по вершинам, либо по соединениям рёбер. Объединение по вершинам происходит, когда две вершины двух разных рёбер попадают в одни и те же ячейки сетки карты. Это довольно быстрая и малозатратная операция. Объединение по соединениям рёбер происходит во втором проходе для всех ещё необъединённых рёбер. Все свободные рёбра проверяются на наличие возможных соединений рёбер как по расстоянию, так и по углу, что требует значительных затрат.
Таким образом, помимо общего правила, требующего как можно меньшего количества рёбер полигонов, следует объединять как можно больше рёбер по вершинам заранее, чтобы для более затратного расчёта рёберных соединений оставалось лишь несколько рёбер. Отладочный Navigation PerformanceMonitor можно использовать для получения статистики о количестве доступных полигонов и рёбер, а также о том, сколько из них не объединены или не объединены по вершинам. Если соотношение между объединёнными вершинами и рёберными соединениями сильно отличается (число вершин должно быть значительно выше), навигационные сетки создаются или размещаются крайне неэффективно.