reckfellENGINE

Occlusion culling: объекты за непрозрачной стеной

Проверить отсечение по реальному списку отрисовки и не скрыть видимую геометрию неправильным occluder.

На этой странице

Что отсекается

Occlusion culling исключает полностью закрытые объекты из отрисовки. Это отличается от выхода за фрустум камеры и от выбора mesh LOD. Непрозрачная стена может уже закрывать пиксели сферы, но без occlusion сфера всё ещё передаётся в отрисовку и отбрасывается проверкой глубины.

Для culling нужен OccluderInstance3D с геометрией перекрытия. Одна видимая MeshInstance3D-стена не создаёт его автоматически. Occluder сам не рисует стену и не создаёт физическое тело.

Запустить полный пример

Используйте три файла из mesh LOD: GeneratedLodMesh.cs, CountedMesh3D.cs и OptimizationLab3D.cs. Нужны настроенный C#-проект, SDK 1.0.0 и net10.0. Выполните dotnet build и назначьте OptimizationLab3D.cs Entity3D-корню .rscene. До запуска выберите Preview=Occlusion.

Полный файл уровня ниже создаёт видимую стену 5×5 и отдельный QuadOccluder3D 4.9×4.9 в той же плоскости. Небольшой запас оставляет occluder внутри непрозрачной стены. UseOcclusionCulling включается у viewport, который рисует уровень.

OptimizationLab3D.cs
C#
using Reckfell;

public partial class OptimizationLab3D : Entity3D
{
    public enum PreviewMode { MeshLod, Occlusion }
    [Export] public PreviewMode Preview { get; set; } = PreviewMode.MeshLod;
    public CountedMesh3D Target { get; private set; } = null!;
    public Camera3D Camera { get; private set; } = null!;
    public MeshInstance3D Wall { get; private set; } = null!;
    public OccluderInstance3D Occluder { get; private set; } = null!;
    private Label counter = null!;

    public override void _Ready()
    {
        var material = new StandardMaterial3D
        {
            AlbedoColor = Colors.White,
            ShadingMode = BaseMaterial3D.ShadingModeEnum.Unshaded
        };
        Target = new CountedMesh3D { Mesh = GeneratedLodMesh.Source().GetMesh(), MaterialOverride = material };
        AddChild(Target);
        var body = new StaticBody3D();AddChild(body);
        body.AddChild(new CollisionShape3D { Shape = new SphereShape3D { Radius = 1 } });
        Wall = new MeshInstance3D
        {
            Mesh = new BoxMesh { Size = new Vector3(5, 5, 0.2f) },
            Position = new Vector3(0, 0, 2), Visible = Preview == PreviewMode.Occlusion,
            MaterialOverride = new StandardMaterial3D
            {
                AlbedoColor = new Color(0.08f, 0.25f, 1),
                ShadingMode = BaseMaterial3D.ShadingModeEnum.Unshaded
            }
        };
        Occluder = new OccluderInstance3D
        {
            Occluder = new QuadOccluder3D { Size = new Vector2(4.9f, 4.9f) },
            Position = new Vector3(0, 0, 2), Visible = Preview == PreviewMode.Occlusion
        };
        AddChild(Wall);AddChild(Occluder);
        Camera = new Camera3D { Current = true, Position = new Vector3(0, 0, 6), Fov = 60, Far = 200 };
        AddChild(Camera);
        var canvas = new CanvasLayer();AddChild(canvas);
        counter = new Label { Position = new Vector2(12, 12) };canvas.AddChild(counter);
        GetViewport().UseOcclusionCulling = Preview == PreviewMode.Occlusion;
    }
    public override void _Process(double delta)
    {
        counter.Text = "△ " + GetViewport().GetRenderInfo(Viewport.RenderInfoType.Visible, Viewport.RenderInfo.PrimitivesInFrame);
    }
}

Preview читается в _Ready. Для проверок после запуска доступны Wall, Occluder, Camera и Target; их нельзя использовать до создания в _Ready. Экспортированное Preview не является готовым переключателем во время игры.

Сравнить результат и стоимость отрисовки

Стена закрывает сферу, occlusion выключен: счётчик включает скрытую геометрию

Occlusion включён: видимая сцена та же, счётчик меньше

В проверке камера находится перед стеной; автоматический LOD отключён порогом 0, чтобы не смешивать два эффекта. Visible ObjectsInFrame уменьшился с 2 до 1, а пиксели сцены ниже счётчика остались одинаковыми. △ показывает примитивы, поэтому число меняется сильнее, чем количество объектов.

Получены реальные кадры и счётчики в текущих Compatibility/OpenGL и Forward+/Vulkan. Публичные изображения — исходные OpenGL-кадры 512×384, не wireframe редактора и не замер FPS. Для собственного уровня измеряйте итоговое время CPU/GPU: подготовка culling тоже имеет стоимость, особенно если почти всё видно.

Проверить правильность occluder

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

В тесте скрытие Wall при оставленном активном Occluder продолжило скрывать сферу. Это ожидаемый результат неверных данных, а не доказательство отсутствия сферы. Отключение Occluder.Visible восстановило её. Для движущейся/удаляемой стены согласованно обновляйте её occluder.

Камера сбоку: сфера снова видна при включённом culling

Проверены восстановление цели при обходе стены камерой и IgnoreOcclusionCulling=true у меша. Последнее возвращает объект в список отрисовки, но не делает его видимым сквозь непрозрачную стену и не отключает остальные виды culling.

Для запечённых occluder BakeMask выбирает визуальные слои собираемой геометрии, не физические CollisionLayer. BakeSimplificationDistance управляет упрощением, не дистанцией от камеры. Кнопки bake и качество результата для реального импортированного уровня в этом примере не проверены; используемый Quad назначается напрямую.

Что продолжает работать

Скрытая сфера осталась Visible=true и IsVisibleInTree=true, продолжила _Process, а физический луч продолжил попадать в её отдельное тело. Occlusion не удаляет Entity, не останавливает игровые таймеры и не выгружает ресурсы.

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

Диагностика

ПроблемаПроверка
Счётчик не уменьшается за стенойНужный viewport, UseOcclusionCulling, действующий Occluder и полное перекрытие объекта
Объект пропал в открытом местеСлишком большой/устаревший occluder, закрытые им проёмы и преобразования
Виден кусок объекта, culling не происходитЧастично видимый объект должен оставаться в отрисовке
Bool включён, FPS прежнийСравнить render list и время CPU/GPU; не выводить ускорение из одного флага
Невидимый объект всё ещё считает логикуЭто ожидаемо: обработка Entity не выключается

OccluderInstance3D API · Viewport API

Документация Reckfell EngineНаверх ↑
БЫСТРЫЙ ПЕРЕХОДНачало работыEntity и иерархияC# & .NET 10Сцены и префабы
Руководства и полный API Reckfell K
reckfellENGINE
RECKFELL ACCOUNT

Вход в аккаунт

Войдите в аккаунт Reckfell.

Один аккаунт для всей платформы Reckfell.