Frustum culling: автоматика и ручное управление

Frustum Culling: автоматика и ручное управление

Frustum culling — это важный аспект оптимизации графических движков, который используется для исключения объектов, находящихся вне поля зрения камеры, из процесса рендеринга. В PlayCanvas эта технология активно используется для улучшения производительности, поскольку рендеринг объектов, которые не видны, только замедляет работу приложения. В этой главе рассматриваются автоматические и ручные способы реализации frustum culling в PlayCanvas.

PlayCanvas автоматически управляет frustum culling для большинства объектов, таких как модели и камеры. Когда сцена загружается, движок автоматически вычисляет, какие объекты находятся внутри видового фрустра (или конуса зрения) камеры, и исключает из рендеринга те, которые находятся за пределами фрустра.

Как работает автоматический culling

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

Для объектов с высокой сложностью модели или объектов, которые часто изменяют своё положение (например, динамичные объекты), автоматический frustum culling помогает значительно снизить нагрузку на систему.

Ручное управление Frustum Culling

PlayCanvas предоставляет возможность тонкой настройки поведения frustum culling. Несмотря на то, что автоматическая система работает эффективно, в некоторых случаях разработчики могут захотеть вручную контролировать, какие объекты должны рендериться, а какие — нет. Это особенно важно в случаях с кастомизированными камерами, уникальными эффектами или нестандартными механиками видимости.

Проверка видимости вручную

Для того чтобы вручную управлять видимостью объектов относительно камеры, можно использовать методы, предоставляемые API PlayCanvas. Один из таких методов — pc.Frustum.contains() — позволяет определить, находится ли объект внутри видового фрустра.

Пример использования:

var cameraEntity = this.app.root.findByName('Camera');
var frustum = cameraEntity.camera.frustum;
var modelEntity = this.app.root.findByName('MyModel');

// Проверяем, находится ли объект в поле зрения камеры
if (frustum.contains(modelEntity.getPosition())) {
    modelEntity.enabled = true;  // Отображаем объект
} else {
    modelEntity.enabled = false; // Скрываем объект
}

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

Использование кастомных фрустра

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

Пример создания кастомного фрустра:

var customFrustum = new pc.Frustum();
customFrustum.setFromMatrix(cameraEntity.camera.viewProjection);

// Проверяем, находится ли объект в кастомном фрустре
if (customFrustum.contains(modelEntity.getPosition())) {
    modelEntity.enabled = true;
} else {
    modelEntity.enabled = false;
}

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

Поддержка LOD (Level of Detail)

Использование фрустра в PlayCanvas также поддерживает работу с механизмами LOD (уровень детализации). Когда объекты находятся далеко от камеры, их рендеринг может быть выполнен с низким уровнем детализации. Это помогает снизить нагрузку на процессор и графический адаптер. В PlayCanvas для этого можно настроить несколько уровней детализации моделей и использовать их в зависимости от положения камеры.

Пример использования LOD:

var distance = cameraEntity.getPosition().distance(modelEntity.getPosition());
var lodLevel;

if (distance < 50) {
    lodLevel = 0;  // Высокая детализация
} else if (distance < 100) {
    lodLevel = 1;  // Средняя детализация
} else {
    lodLevel = 2;  // Низкая детализация
}

modelEntity.model.model = lodModels[lodLevel];  // Устанавливаем подходящий уровень детализации

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

Оптимизация с использованием Bounding Volume Hierarchy (BVH)

Для более сложных сцен с большим количеством объектов PlayCanvas предоставляет возможность использовать иерархию ограничивающих объёмов (Bounding Volume Hierarchy, BVH). Эта техника позволяет эффективно организовывать объекты в иерархическую структуру, что ускоряет проверку видимости и уменьшает количество вычислений для frustum culling.

С использованием BVH можно быстрее определить, какие объекты нужно проверять на попадание в фрустр, а какие можно сразу исключить из вычислений. В PlayCanvas это может быть реализовано через более сложные системы, например, с использованием заранее подготовленных данных для Bounding Box или других геометрических примитивов.

Заключение

Frustum culling в PlayCanvas предоставляет мощные инструменты для оптимизации рендеринга и управления производительностью в реальном времени. Автоматическая система culling работает эффективно для большинства объектов, но для более сложных сценариев, требующих высокой гибкости, можно использовать ручные методы управления видимостью. Кастомизация фрустра, использование LOD и внедрение BVH — все эти техники позволяют добиться значительного улучшения производительности при создании сложных 3D-приложений.