Skip to content

26.3 Temporal Hysteresis and Zero Allocation

Dasik edited this page Aug 20, 2026 · 1 revision

⏱️ Temporal Hysteresis & Zero-Allocation Math (Minecraft 26.3)

High-speed occlusion culling can introduce two common performance flaws:

  1. Camera-Grazing Flicker (Z-Fighting / Boundary Pop-in): Small camera rotations or walking view-bobbing crossing a block edge can cause entities to rapidly flicker between rendered and unrendered states on alternating frames.
  2. Garbage Collection Stutter Spikes: Continuous allocation of new Vec3() and bounding box objects during raycasting triggers frequent JVM Young-Gen garbage collection pauses.

Camera Culling solves both issues with an Adaptive Distance-Scaled Grace Buffer and a Zero-Allocation Hot-Path Engine.


📋 Hysteresis & Allocation Infobox

Property Value
Near Distance Grace Buffer $d \le 32\text{m} \implies 4\text{ consecutive occluded frames}$
Medium Distance Grace Buffer $32\text{m} < d \le 64\text{m} \implies 8\text{ consecutive occluded frames}$
Far Distance Grace Buffer $d > 64\text{m} \implies 12\text{ consecutive occluded frames}$
Visibility Transition Instantaneous ($0\text{ frame delay}$) upon establishing sightline
Tracking Structure it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap (Zero boxing overhead)
Per-Frame Allocations $0\text{ bytes}$ (Primitive double coordinates passed directly)

📐 Distance-Scaled Grace Buffer Formula

The required occlusion streak before transitioning an entity to the [CULLED] state is computed by:

$$\text{RequiredStreak}(d) = \begin{cases} 12\text{ frames} & \text{if } d^2 > 64.0^2 \ (4096.0\text{m}^2) \\ 8\text{ frames} & \text{if } d^2 > 32.0^2 \ (1024.0\text{m}^2) \\ 4\text{ frames} & \text{if } d^2 \le 32.0^2 \end{cases}$$

[ENTITY SIGHTLINE LOST]
       │
       ├── Frame 1 occluded ──► RENDER (Grace Decay)
       ├── Frame 2 occluded ──► RENDER (Grace Decay)
       ├── Frame 3 occluded ──► RENDER (Grace Decay)
       └── Frame 4 occluded ──► CULL (Streak Met)
  • Instant Unculling: As soon as a single raycast sample establishes a clear line of sight, the occlusion streak is removed (OCCLUDED_STREAK.remove(id)), making the entity visible immediately with $0\text{ frame latency}$.
  • Asymmetric Decay: Becoming occluded requires multiple consecutive frames; becoming visible takes 1 frame. This eliminates all camera-turning flicker.

⚡ Zero-Allocation Primitive Architecture

In CullingRaycastHelper.java, intermediate vector heap allocations are completely eliminated:

// Zero heap allocations: coordinates are passed as raw primitive doubles
public static boolean hasLineOfSight(Level level, Vec3 from, double toX, double toY, double toZ) {
    Vec3 to = new Vec3(toX, toY, toZ);
    ClipContext ctx = new ClipContext(from, to, ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, CollisionContext.empty());
    BlockHitResult hit = level.clip(ctx);
    if (hit.getType() == HitResult.Type.MISS) {
        return true;
    }
    // Floor hit & tolerance evaluation with zero object construction
    ...
}

🔗 Related Pages

Clone this wiki locally