SleakEngine 1.0.0
C++23 multi-backend game engine
Loading...
Searching...
No Matches
Sleak::CullingSystem Class Reference

#include <CullingSystem.hpp>

Classes

struct  Stats
 Per-frame counters for the last completed culling pass. More...

Static Public Member Functions

static void BeginFrame (const ViewFrustum &frustum, const Math::Matrix4 &viewProj, const Math::Vector3D &cameraPos)
static void FinalizeOccluders ()
 Sorts submitted occluders by distance and rasterizes them into the depth buffer up to the max-occluder budget.
static const float * GetDepthBuffer (uint32_t &width, uint32_t &height)
static const StatsGetStats ()
static bool IsFrustumCullingEnabled ()
static bool IsOcclusionCullingEnabled ()
static bool IsVisible (const Math::AABB &box)
static bool IsVisibleFrustumOnly (const Math::AABB &box)
 Frustum-only visibility test, skipping the occlusion buffer entirely.
static void SetAdaptiveOcclusion (bool enabled, uint32_t probeInterval)
static void SetFrustumCullingEnabled (bool enabled)
static void SetMaxOccluders (uint32_t count)
static void SetOcclusionBufferSize (uint32_t width, uint32_t height)
 Occlusion depth buffer resolution (default 256x144).
static void SetOcclusionCullingEnabled (bool enabled)
static void Shutdown ()
static void SubmitOccluderBox (const Math::AABB &box)
 World-space occluders. Boxes must be fully solid volumes.
static void SubmitOccluderTriangles (const Math::Vector3D *vertices, uint32_t vertexCount, const uint32_t *indices, uint32_t indexCount)
 World-space triangle occluder; same fully-solid-volume requirement as SubmitOccluderBox.

Detailed Description

CPU visibility system: view-frustum culling plus software occlusion culling against a low-resolution depth buffer rasterized from game-submitted occluder volumes. Backend-agnostic (no GPU work).

Frame protocol:

  1. BeginFrame(...) once per frame after camera update (the engine calls this automatically from the main camera)
  2. SubmitOccluderBox/Triangles any number of world-space occluders
  3. FinalizeOccluders() sort by distance, rasterize budget
  4. IsVisible(aabb) frustum + occlusion query Steps 2-3 are optional; IsVisible degrades to frustum-only.

Everything here is static and lives for the process. The main camera calls BeginFrame() for you during its update, so a game that only wants frustum culling can call IsVisible() and stop reading here.

Occlusion culling is the part you opt into. Submit occluder volumes every frame, call FinalizeOccluders() once, then test your objects. Occluders must be fully solid volumes: a box submitted over a cave or an open doorway will hide geometry that should be visible. The bounds you test with should be tight around the real vertex extent, since bounds that overshoot into empty space pass the depth test and cull nothing while still costing you the test.

The occlusion pass adapts. When a rasterized frame culls nothing, it stops rasterizing and probes again every probeInterval frames, with queries falling back to frustum-only in between. GetStats() reports what the last pass actually did.

// Optional tuning, once at startup
// Every frame, after the camera has updated
for (const auto& chunk : loadedChunks) {
for (const auto& solid : chunk.solidVolumes) {
}
}
for (auto& chunk : loadedChunks) {
chunk.visible = Sleak::CullingSystem::IsVisible(chunk.bounds);
}
const auto& stats = Sleak::CullingSystem::GetStats();
SLEAK_LOG("culled {} by frustum, {} by occlusion",
stats.frustumCulled, stats.occlusionCulled);
#define SLEAK_LOG(...)
Definition Logger.hpp:19
static const Stats & GetStats()
static void SetAdaptiveOcclusion(bool enabled, uint32_t probeInterval)
static void SetOcclusionBufferSize(uint32_t width, uint32_t height)
Occlusion depth buffer resolution (default 256x144).
static void SetOcclusionCullingEnabled(bool enabled)
static void SubmitOccluderBox(const Math::AABB &box)
World-space occluders. Boxes must be fully solid volumes.
static bool IsVisible(const Math::AABB &box)
static void FinalizeOccluders()
Sorts submitted occluders by distance and rasterizes them into the depth buffer up to the max-occlude...
static void SetMaxOccluders(uint32_t count)
See also
ViewFrustum, Camera, Math::AABB

Definition at line 68 of file CullingSystem.hpp.

Member Function Documentation

◆ BeginFrame()

void Sleak::CullingSystem::BeginFrame ( const ViewFrustum & frustum,
const Math::Matrix4 & viewProj,
const Math::Vector3D & cameraPos )
static

viewProj uses the engine row-vector convention: clip = point * VP, depth range [0, w]. cameraPos is world-space.

Definition at line 312 of file CullingSystem.cpp.

◆ FinalizeOccluders()

void Sleak::CullingSystem::FinalizeOccluders ( )
static

Sorts submitted occluders by distance and rasterizes them into the depth buffer up to the max-occluder budget.

Definition at line 386 of file CullingSystem.cpp.

◆ GetDepthBuffer()

const float * Sleak::CullingSystem::GetDepthBuffer ( uint32_t & width,
uint32_t & height )
static

Debug: row-major width*height floats, NDC depth (0 near, 1 far). Returns nullptr if occlusion has never rasterized.

Definition at line 472 of file CullingSystem.cpp.

◆ GetStats()

const CullingSystem::Stats & Sleak::CullingSystem::GetStats ( )
static

Definition at line 468 of file CullingSystem.cpp.

◆ IsFrustumCullingEnabled()

bool Sleak::CullingSystem::IsFrustumCullingEnabled ( )
static

Definition at line 286 of file CullingSystem.cpp.

◆ IsOcclusionCullingEnabled()

bool Sleak::CullingSystem::IsOcclusionCullingEnabled ( )
static

Definition at line 290 of file CullingSystem.cpp.

◆ IsVisible()

bool Sleak::CullingSystem::IsVisible ( const Math::AABB & box)
static

Frustum test, then conservative depth test against the occlusion buffer. Never falsely culls a visible box (given valid occluders).

Definition at line 435 of file CullingSystem.cpp.

◆ IsVisibleFrustumOnly()

bool Sleak::CullingSystem::IsVisibleFrustumOnly ( const Math::AABB & box)
static

Frustum-only visibility test, skipping the occlusion buffer entirely.

Definition at line 455 of file CullingSystem.cpp.

◆ SetAdaptiveOcclusion()

void Sleak::CullingSystem::SetAdaptiveOcclusion ( bool enabled,
uint32_t probeInterval )
static

Adaptive occlusion (default on, interval 20): when a rasterized frame culls nothing, skip rasterization for probeInterval frames and probe again. Queries degrade to frustum-only while skipping.

Definition at line 304 of file CullingSystem.cpp.

◆ SetFrustumCullingEnabled()

void Sleak::CullingSystem::SetFrustumCullingEnabled ( bool enabled)
static

Definition at line 278 of file CullingSystem.cpp.

◆ SetMaxOccluders()

void Sleak::CullingSystem::SetMaxOccluders ( uint32_t count)
static

Max occluders rasterized per frame after the distance sort (default 192).

Definition at line 300 of file CullingSystem.cpp.

◆ SetOcclusionBufferSize()

void Sleak::CullingSystem::SetOcclusionBufferSize ( uint32_t width,
uint32_t height )
static

Occlusion depth buffer resolution (default 256x144).

Definition at line 294 of file CullingSystem.cpp.

◆ SetOcclusionCullingEnabled()

void Sleak::CullingSystem::SetOcclusionCullingEnabled ( bool enabled)
static

Definition at line 282 of file CullingSystem.cpp.

◆ Shutdown()

void Sleak::CullingSystem::Shutdown ( )
static

Definition at line 484 of file CullingSystem.cpp.

◆ SubmitOccluderBox()

void Sleak::CullingSystem::SubmitOccluderBox ( const Math::AABB & box)
static

World-space occluders. Boxes must be fully solid volumes.

Definition at line 337 of file CullingSystem.cpp.

◆ SubmitOccluderTriangles()

void Sleak::CullingSystem::SubmitOccluderTriangles ( const Math::Vector3D * vertices,
uint32_t vertexCount,
const uint32_t * indices,
uint32_t indexCount )
static

World-space triangle occluder; same fully-solid-volume requirement as SubmitOccluderBox.

Definition at line 351 of file CullingSystem.cpp.