/**
 * Occlusion culling against a hierarchical depth buffer (HZB), on by default.
 *
 * Per frame, before the cut is computed:
 *  1. occluder pass - the occluder meshes' previous-frame camera cuts (their index buffers still hold them)
 *     are drawn depth-only with the CURRENT camera into a small depth target. That geometry was visible last
 *     frame, so it is a subset of the real occluders.
 *  2. HZB build - mip 0 is that depth (copied into a storage buffer), each further mip is the MAX of its
 *     2x2 children: a texel only hides what lies behind all of its occluders.
 *  3. cull - an instance or meshlet sphere is dropped from the camera cut when its projected box, read at
 *     the mip where it covers at most 2x2 texels, is entirely behind the max depth there.
 *
 * Why it is safe: removing occluders can only push the depth buffer back, so anything hidden by the subset
 * is hidden by the full scene. Stale or missing occluders cost efficiency, never correctness. The occluders
 * are LOD-simplified (they may bulge up to the error threshold in front of the true surface), so the tested
 * sphere is grown by that error first.
 *
 * Only meshes flagged `occluder` are drawn in step 1 (by default: opaque, single-sided, no alpha test, i.e.
 * solid geometry such as terrain, rocks, buildings; foliage is mostly holes). Every mesh is tested, unless
 * its `occlusionCulling` is off. Shadow cuts are never occlusion culled: a caster hidden from the camera can
 * still shadow something visible.
 *
 * Storage: the whole HZB (a header with each mip's offset and size, then all mips) is one storage buffer,
 * sized for `maxSize`, so nothing is reallocated on resize.
 */
import * as THREE from 'three/webgpu';
import type { VirtualMesh } from './VirtualMesh.js';
type Node = any;
export declare class OcclusionCulling {
    /** Lever: set false to turn occlusion culling off (no occluder pass, no HZB, nothing culled by it). */
    enabled: boolean;
    /**
     * Lever: decide by measurement. Whether occlusion pays off depends on the scene and the GPU: the occluder
     * pass has a fixed cost, which wins in cities and interiors and loses in open landscapes. With `auto`,
     * frame times are compared with occlusion off and on (`autoProbeFrames` each), the faster setting is kept
     * for `autoHoldFrames`, then measured again. Within 3% (e.g. both capped by vsync) it stays off.
     * Set false to keep it on whenever `enabled`.
     */
    auto: boolean;
    autoProbeFrames: number;
    autoHoldFrames: number;
    /** The auto setting currently in use (true: occlusion on). */
    autoChoice: boolean;
    private phase;
    private phaseFrames;
    private samples;
    private offMean;
    private lastTick;
    /** Depth resolution relative to the drawing buffer. Lower is cheaper and culls a little less. */
    resolutionScale: number;
    /** Largest HZB dimension in texels (memory ~1.33 * maxSize^2 * 4 bytes). */
    readonly maxSize: number;
    /** True when this frame's HZB holds at least one occluder (the cull kernels test against it only then). */
    active: boolean;
    /** 1 while this frame's HZB is valid; the cull kernels only occlusion-cull then. */
    readonly activeNode: THREE.UniformNode<"uint", number>;
    private readonly depthScene;
    private readonly proxies;
    private readonly projection;
    private readonly near;
    private readonly levelCapacity;
    private readonly levelOffsets;
    private readonly hzbAttribute;
    private readonly hzbWrite;
    private readonly hzbRead;
    /** Copy + reduce kernels for the current depth size, dispatched with this frame's cut (one submission). */
    private buildNodes;
    private renderTarget;
    private width;
    private height;
    private levels;
    private readonly bufferSize;
    constructor(projection: Node, near: Node, maxSize?: number);
    /**
     * True only when a sphere (view-space center, radius) is certainly hidden. Any doubt (touching the near
     * plane, outside the screen) keeps it.
     */
    occluded(viewCenter: Node, radius: Node): Node;
    /** Called once per frame by the context: feeds the auto A/B measurement (see `auto`). */
    tick(now: number): void;
    private next;
    private autoWanted;
    /** Depth-only proxy of a mesh's camera cut, created on first use and kept in sync with its pool. */
    private proxyOf;
    unregisterMesh(mesh: VirtualMesh): void;
    /**
     * Whether occlusion culling runs this frame (enabled, a supported camera and depth mode, and the auto tuner
     * wants it). Meshes get their per-mesh flag from this before the cut is computed.
     */
    wantsFrame(renderer: THREE.WebGPURenderer, camera: THREE.Camera, _frame: number): boolean;
    /**
     * Renders the occluders' last camera cuts into the depth target and returns the compute kernels that turn
     * it into the HZB; run them before the cut (the caller prepends them to the same compute submission).
     * Sets `activeNode`, which the cull kernels check: without occluders this frame, nothing is occlusion culled.
     */
    beginFrame(renderer: THREE.WebGPURenderer, camera: THREE.Camera, meshes: readonly VirtualMesh[]): THREE.ComputeNode[];
    private resize;
    dispose(): void;
}
export {};
