Отбраковка окклюзии
В движке 3D-рендеринга occlusion culling — это процесс удаления скрытой геометрии.
В этом руководстве вы узнаете:
Каковы преимущества и недостатки метода occlusion culling (окклюзионной выборки).
Как настроить occlusion culling (Окклюзивного обрезания) в Godot.
Устранение распространенных проблем с occlusion culling.
См. также
Вы можете увидеть, как работает отбраковка окклюзии, используя Демонстрационный проект Occlusion Culling и Mesh LOD.
Зачем использовать окклюзионную выборку (обрезание)
В этом примере сцены с сотнями комнат, расположенных рядом друг с другом, динамический объект (красная сфера) спрятан за стеной в освещенной комнате (слева от двери):
Пример сцены с макетом, дружественным к occlusion culling
При отключенном occlusion culling все комнаты за освещенной комнатой должны быть визуализированы. Динамический объект также должен быть визуализирован:
Пример сцены с неработоспособным occlusion culling (каркас)
При включенном occlusion culling рендерить нужно только те комнаты, которые действительно видны. Динамический объект также закрыт стеной, и поэтому его больше не нужно рендерить:
Пример сцены с включенным occlusion culling (каркас)
Так как движку нужно сделать меньше работы (меньше вершин для рендеринга и меньше вызовов отрисовки), производительность будет расти, пока в сцене достаточно возможностей для отсечения окклюзии. Это означает, что отсечение окклюзии наиболее эффективно в сценах внутри помещений, предпочтительно с большим количеством небольших комнат вместо меньшего количества больших комнат. Объедините это с Уровень детализации сетки (LOD) и Диапазоны видимости (HLOD), чтобы еще больше повысить производительность.
Примечание
При использовании рендерера Forward+ движок уже выполняет depth prepass. Он заключается в рендеринге версии сцены только с глубиной перед рендерингом фактических материалов сцены. Это используется для того, чтобы гарантировать, что каждый непрозрачный пиксель затеняется только один раз, что значительно снижает стоимость перерисовки.
Наибольшие преимущества производительности можно наблюдать при использовании мобильного рендерера, поскольку он не имеет предварительного прохода глубины по соображениям производительности. В результате, occlusion culling будет активно уменьшать перерисовку затенения с этим рендерером.
Тем не менее, даже при использовании предварительного прохода глубины, все еще есть заметное преимущество occlusion culling в сложных 3D-сценах. Однако в сценах с небольшим количеством возможностей occlusion culling occlusion culling может не стоить дополнительных настроек и использования CPU.
Как работает Окклюзивное обрезание в Godot
Примечание
"occluder" относится к форме, блокирующей обзор, в то время как "occludee" относится к скрываемому объекту.
В Godot, occlusion culling работает путем растеризации геометрии occluder сцены в буфер низкого разрешения на CPU. Это делается с помощью библиотеки программной трассировки лучей Embree.
Затем движок использует этот буфер низкого разрешения для проверки AABB occludee против форм occluder. AABB occludee должен быть полностью закрыт формой occluder, чтобы быть отсеченным.
В результате, более мелкие объекты с большей вероятностью будут эффективно отбракованы, чем более крупные. Более крупные окклюдеры (например, стены) также, как правило, гораздо более эффективны, чем более мелкие (например, декоративный реквизит).
Настройка Окклюзивного обрезания
Первым шагом к использованию occlusion culling является включение настройки проекта Rendering > **Occlusion Culling > Use Occlusion Culling. (Убедитесь, что переключатель Advanced включен в диалоговом окне Project Settings, чтобы его можно было увидеть.)
Эта настройка проекта применяется немедленно, поэтому вам не нужно перезапускать редактор.
После включения настройки проекта вам все еще нужно создать несколько окклюдеров. По соображениям производительности движок не использует автоматически всю видимую геометрию в качестве основы для occlusion culling. Вместо этого движок требует упрощенного представления сцены, в которой будут запекаться только статические объекты.
Существует два способа установки окклюдеров в сцене:
Автоматическое запекание окклюдеров (рекомендуется)
Примечание
В процессе запекания occluder в настоящее время учитываются только узлы MeshInstance3D. Узлы MultiMeshInstance3D, GPUParticles3D, CPUParticles3D и CSG не учитываются при запекании окклюдеров. Если вы хотите, чтобы они рассматривались как окклюдеры, вам придется вручную создать формы окклюдеров, которые (примерно) соответствуют их геометрии.
Начиная с Godot 4.4, узлы CSG можно учитывать в процессе запекания, если они converted to a MeshInstance3D перед запеканием окклюдеров.
Это ограничение не распространяется на occludees. Любой тип узла, который наследуется от GeometryInstance3D, может быть occluded.
После включения настройки проекта occluderculling, упомянутой выше, добавьте узел OccluderInstance3D в сцену, содержащую ваш 3D-уровень.
Выберите узел OccluderInstance3D, затем нажмите Bake Occluders в верхней части окна просмотра 3D-редактора. После запекания узел OccluderInstance3D будет содержать ресурс Occluder3D, который хранит упрощенную версию геометрии вашего уровня. Эта геометрия окклюдера отображается в виде фиолетовых линий каркаса в 3D-виде (при условии, что View Gizmos включен в меню Perspective). Затем эта геометрия используется для обеспечения окклюзивного обрезания как для статических, так и для динамических окклюдеров.
После запекания вы можете заметить, что ваши динамические объекты (такие как игрок, враги и т. д.) включены в запеченную сетку. Чтобы предотвратить это, установите свойство Bake > Cull Mask на OccluderInstance3D, чтобы исключить определенные визуальные слои из запекания.
Например, вы можете отключить слой 2 на маске отбраковки, а затем настроить узлы MeshInstance3D динамических объектов так, чтобы они располагались на визуальном слое 2 (вместо слоя 1). Для этого выберите нужный узел MeshInstance3D, затем в свойстве VisualInstance3D > Layers снимите отметку со слоя 1, а затем отметьте слой 2. После настройки маски отбраковки и слоев снова запеките окклюдеры, следуя описанному выше процессу.
Ручная установка окклюдеров
Этот подход больше подходит для специализированных случаев использования, таких как создание окклюзии для установок MultiMeshInstance3D или узлов CSG (из-за вышеупомянутого ограничения).
После включения настройки проекта occlusion culling, упомянутой выше, добавьте узел OccluderInstance3D в сцену, содержащую ваш 3D-уровень. Выберите узел OccluderInstance3D, затем выберите тип occluder для добавления в свойстве Occluder:
QuadOccluder3D (одна плоскость)
BoxOccluder3D (кубоид)
SphereOccluder3D (сферический окклюдер)
PolygonOccluder3D (2D-полигон с любым количеством точек)
Существует также ArrayOccluder3D, точки которого нельзя изменять в редакторе, но они могут быть полезны для процедурной генерации из скрипта.
Предварительный просмотр окклюзии
Вы можете включить режим отладки рисования, чтобы просмотреть, что на самом деле «видит» occlusion culling. В верхнем левом углу окна просмотра 3D-редактора нажмите кнопку Perspective (или Orthogonal в зависимости от текущего режима камеры), затем выберите Display Advanced… > Occlusion Culling Buffer. Это отобразит буфер низкого разрешения, который используется движком для occlusion culling.
В этом же меню вы также можете включить Просмотр информации и Просмотр времени кадра, чтобы просмотреть количество вызовов отрисовки и отрисованных примитивов (вершины + индексы) в правом нижнем углу, а также количество отрисованных кадров в секунду в правом верхнем углу.
Если вы включите occlusion culling в настройках проекта, пока отображается эта информация, вы увидите, насколько occlusion culling улучшает производительность вашей сцены. Обратите внимание, что выигрыш в производительности сильно зависит от угла обзора камеры 3D-редактора, так как occlusion culling эффективен только в том случае, если перед камерой есть окклюдеры.
Чтобы включить отсечение окклюзии во время выполнения, установите use_occlusion_culling в корневом окне просмотра следующим образом:
get_tree().root.use_occlusion_culling = true
GetTree().Root.UseOcclusionCulling = true;
Включение и выключение функции occlusion culling (Окклюзивное обрезание) во время выполнения полезно для сравнения производительности в работающем проекте.
Компенсация производительности
Спроектируйте свои уровни так, чтобы использовать преимущества окклюзивного обрезания
Это самое важное правило. Хороший дизайн уровня — это не только то, что требует игровой процесс; он также должен быть создан с учетом окклюзии (ограничений).
В помещениях добавьте непрозрачные стены, чтобы «разрывать» линию обзора через равные интервалы и гарантировать, что не слишком большая часть сцены будет видна одновременно.
Для больших открытых сцен используйте пирамидальную структуру для возвышения рельефа, когда это возможно. Это обеспечивает наибольшие возможности отбраковки по сравнению с любой другой формой рельефа.
Избегайте перемещения узлов OccluderInstance3D во время игры
Это включает в себя перемещение родительских узлов OccluderInstance3D, поскольку это приведет к перемещению самих узлов в глобальном пространстве, что потребует перестройки BVH.
Переключение видимости OccluderInstance3D (или видимости одного из его родительских объектов) не так затратно, поскольку обновление необходимо выполнить только один раз (а не постоянно).
Например, если у вас есть раздвижная или вращающаяся дверь, вы можете сделать узел OccluderInstance3D не дочерним элементом самой двери (чтобы окклюдер никогда не двигался), но вы можете скрыть видимость OccluderInstance3D, как только дверь начнет открываться. Затем вы можете повторно отобразить OccluderInstance3D, как только дверь полностью закроется.
Если вам действительно необходимо переместить узел OccluderInstance3D во время игры, используйте для него примитивную форму Occluder3D вместо сложной запеченной формы.
Используйте максимально простые формы окклюдеров
Если вы заметили низкую производительность или подтормаживания в сложных 3D-сценах, это может означать, что процессор перегружен в результате рендеринга детализированных окклюдеров. Выберите узел OccluderInstance3D, увеличьте свойство Bake > Simplification, затем снова запеките окклюдеры.
Помните, что необходимо поддерживать разумное значение упрощения. Значения, которые слишком высоки для геометрии уровня, могут привести к неправильному отсечению окклюзии, как в Мой окклюдер отбраковывается, когда этого не должно быть.
Если это все еще не приводит к достаточно низкому использованию CPU, вы можете попробовать настроить Rendering > Occlusion Culling > BVH Build Quality проектные настройки и/или уменьшить Rendering > Occlusion Culling > Occlusion Rays Per Thread. Вам нужно будет включить переключатель Advanced в диалоговом окне Project Settings, чтобы увидеть эти настройки.
Устранение неполадок
Мой окклюдер не уничтожается, когда это необходимо
Со стороны окклюдера:
Во-первых, дважды проверьте, что свойство Bake > Cull Mask в OccluderInstance3D установлено для разрешения запекания нужных вам сеток. Слой видимости узлов MeshInstance3D должен присутствовать в маске отсечения, чтобы сетка была включена в запекание.
Также обратите внимание, что запекание окклюдера учитывает только сетки с непрозрачными материалами. Поверхности с прозрачными материалами не будут включены в запекание, даже если примененная к ним текстура полностью непрозрачна.
Наконец, помните, что узлы MultiMeshInstance3D, GPUParticles3D, CPUParticles3D и CSG не учитываются при запекании окклюдеров. В качестве обходного пути вы можете вручную добавить для них узлы OccluderInstance3D.
На окклюдированной стороне:
Убедитесь, что Extra Cull Margin (Дополнительное поле отбраковки) установлено как можно ниже (обычно оно должно быть равно 0.0), а параметр Ignore Occlusion Culling (Игнорировать отбраковку перекрытий) отключен в разделе GeometryInstance3D объекта.
Также проверьте размер AABB (который представлен оранжевым полем при выборе узла). Этот выровненный по оси ограничивающий прямоугольник должен быть полностью закрыт формами окклюдера, чтобы окклюдер был скрыт.
Мой окклюдер отбраковывается, когда этого не должно быть
Наиболее вероятной причиной этого является то, что объекты, включенные в запекание окклюдера, были перемещены после запекания окклюдеров. Например, это может произойти при перемещении геометрии уровня или перераспределении его макета. Чтобы исправить это, выберите узел OccluderInstance3D и запекайте окклюдеры снова.
Это также может произойти, если в запекание были включены динамические объекты, хотя их там быть не должно. Используйте режим отладки отрисовки occlusion culling для поиска форм окклюдера, которые не должны присутствовать, затем соответственно отрегулируйте маску bake culling.
Последняя возможная причина этого — чрезмерно агрессивное упрощение сетки во время процесса запекания окклюдеров. Выберите узел OccluderInstance3D, уменьшите свойство Bake > Simplification, затем запеките окклюдеры снова.
В качестве последнего средства вы можете включить свойство Ignore Occlusion Culling (Игнорировать отсечение окклюзии) на occludee. Это сведет на нет улучшения производительности отсечения окклюзии для этого объекта, но имеет смысл сделать это для объектов, которые никогда не будут отсеиваться (например, модель вида от первого лица).