@equinor/videx-3d
    Preparing search index...

    Class OITRenderPass

    Hybrid order-independent-transparency (OIT) render pass for use with the RenderingPipeline (or any custom composer). Renders the nearest transparent layer exactly (depth-peeled, alpha-over) and the remaining layers using weighted-blended OIT (WBOIT), partitioned per-pixel in view-space linear depth.

    Transparency is opt-in: this pass only affects materials that are OIT-capable (library materials, or stock/user materials patched with makeOitCompatible). Two per-object escape-hatch layers override the default routing: LAYERS.FORCE_OPAQUE draws the object as a depth-writing opaque occluder (its material is temporarily forced to depthWrite=true, transparent=false); LAYERS.OIT_EXCLUDED also draws it in the opaque pass but leaves the material's own properties untouched. Additive/glow objects tagged with the LAYERS.EMISSIVE layer are drawn between the opaque and transparent layers (so transparent surfaces in front attenuate them); always-on-top objects tagged with the LAYERS.OVERLAY layer are drawn last, on top of the resolved transparency. While this pass is active it sets the per-canvas rendering state to 'oit' so components can disable conflicting self-transparency workarounds.

    const passes = useMemo(
    () => [new OITRenderPass(scene, camera), new OutputPass()],
    [scene, camera],
    );
    return <RenderingPipeline passes={passes} />;

    Hierarchy (View Summary)

    Index

    Constructors

    Properties

    antialias: OITAntialiasMode = 'taa'

    Built-in anti-aliasing mode for the composited result.

    • 'none': no built-in AA. Pair with opaqueSamples (MSAA) for opaque-edge AA in an opaque-only close-up; transparent/additive edges stay un-anti-aliased, and MSAA leaves a background-coloured fringe over transparent surfaces (see opaqueSamples).
    • 'temporal': temporal supersampling (see TemporalResolver). The camera is sub-pixel jittered each frame and the composited frame is accumulated into a running average while the camera is still, converging to a genuinely supersampled image (thin trajectory lines, transparent-surface edges, contour lines and the additive highlight all anti-alias). There is no reprojection, so nothing ghosts; while the camera moves the current frame is shown un-jittered (the moving frame is not anti-aliased unless combined with SMAA or MSAA).
    • 'smaa': subpixel morphological AA (see smaaQuality) applied as a spatial post pass every frame. Anti-aliases moving frames too, but (like all morphological techniques) cannot recover sub-pixel features such as 1px lines that fall between samples.
    • 'temporal-smaa': both, mutually exclusive per frame — temporal accumulation while the camera is still (crisp, recovers sub-pixel detail) and SMAA while it moves. SMAA never softens the converged still image and only costs GPU time during motion.
    • 'taa' (default): reprojected temporal anti-aliasing (see TaaResolver). Like 'temporal' the camera is sub-pixel jittered, but the history is reprojected every frame using the nearest visible surface's depth (opaque hardware depth refined by the OIT front-layer depth), so anti-aliasing is retained during camera motion. Ghosting from additive/animated/disoccluded content is bounded by neighbourhood colour clamping. This is the recommended default for the OIT pipeline — it anti-aliases both still and moving frames. Use 'temporal' instead if you need guaranteed ghost-free stills and don't mind losing motion AA.
    • 'fxaa': fast approximate AA (see FxaaResolver) applied as a single cheap spatial post pass every frame. Cheaper and softer than 'smaa', with no OIT or temporal coupling. Like all spatial techniques it cannot recover sub-pixel features. Also available as the standalone FXAAPass for non-OIT (plain RenderPass) setups.

    The jitter is applied to the shared camera only between this pass's own scene render and resolve, so it never leaks to later passes (annotations, picking). This is the OIT pipeline's high-quality AA. Non-OIT setups (plain RenderPass) should use MSAA instead.

    clearAlpha: number = 1
    clearColor: Color | null = null

    Explicit background for passes that clear the frame (e.g. RenderPass and the OIT opaque clear). When set, the pass clears to this colour/alpha instead of the renderer's current clear state, giving a single source of truth so the background is identical regardless of which base pass renders the scene. When null the pass falls back to the renderer's current clear colour/alpha.

    debugTargets: boolean = false

    When true, draws small thumbnails of the internal render targets (min-depth, accumulation) into the bottom-left of the output, for debugging. GPU-only; no pixel readback.

    emitterDepthStamp: boolean = false

    Optional feature (default off): stamp depth for emissive/glow emitters (objects on LAYERS.EMISSIVE) wherever their fragment strength is at least emitterDepthThreshold, drawn before the transparent OIT passes. This lets the dense core of an additive emitter (e.g. perforation jets) occlude transparent surfaces behind it, preventing the wash-out where a far transparent surface would otherwise dim the emitter. Surfaces in front still attenuate it.

    An emitter opts in by exposing a depth-only stamp material on its material's userData.occlusionDepthMaterial (with a uOcclusionThreshold uniform the pass drives). Emitters without one are simply skipped. Costs one extra emissive pass per frame when enabled; nothing when off.

    emitterDepthThreshold: number = 0.5

    Strength threshold (0..1) for emitterDepthStamp. Default 0.5.

    occlusionDepthStamp: boolean = false

    Optional feature (default off): after the transparent OIT passes, stamp depth for transparent surfaces wherever their own alpha is at least occlusionDepthThreshold. Transparent surfaces normally write no depth, so annotation labels behind a high-but-not-full opacity surface are never occluded; enabling this makes a surface occlude labels once its alpha clears the threshold.

    The test is per-fragment and per-surface (each surface judged on its own alpha, not accumulated coverage), and the stamped depth uses the same encoding the AnnotationsPass already samples. Costs one extra transparent-geometry pass per frame when enabled; nothing (not even a shader compile) when off.

    occlusionDepthThreshold: number = 0.5

    Alpha threshold (0..1) for occlusionDepthStamp. Default 0.5.

    opaqueSamples: number = 0

    Number of MSAA samples (0 = off) for the hybrid multisample path. When > 0 the opaque geometry (including fully-opaque OIT occluders such as casings/completion tools), the emissive layer, the weighted-blended (WBOIT) tail composite, the exact front layer and the overlay are all rendered into ONE dedicated multisample target sharing the pipeline depth. The single-sample min-depth/accum aux targets read the opaque depth resolved on the first switch away from the multisample target; the final colour is resolved ONCE more and blitted into the single-sample pipeline buffer (~2 resolves total). This costs more than multisampling the opaque pass alone but far less than multisampling the whole half-float pipeline buffer (~4 resolves). Clamped to renderer.capabilities.maxSamples.

    MSAA is not recommended with OIT. The min-depth/accum aux buffers must be single-sample (WebGL2 cannot sample a multisample texture), so the transparent tail is composited single-sample over the multisample opaque edges. Opaque edges are matted against the cleared background before the transparent surfaces exist, and the single-sample composite cannot reconstruct per-sample coverage — so a background-coloured fringe survives along opaque and thin-line edges over transparent surfaces. This is structural and cannot be made clean here; only supersampling the whole composite (an antialias temporal mode, or the RenderingPipeline supersample prop) removes it.

    opaqueSamples is therefore intended only for the narrow opaque-only close-up (no transparent surfaces composited in front — e.g. a casing detail view), where the fringe cannot occur. For anything with transparent surfaces leave this at 0 and use antialias (temporal / SMAA / TAA / FXAA) or the RenderingPipeline supersample prop instead. (Pipeline-level samples does not anti-alias the OIT result either, and is only for a plain opaque RenderPass pipeline with no OIT.)

    Do not combine opaqueSamples > 0 with an antialias temporal mode ('temporal'/'temporal-smaa'/'taa'): it is wasteful — the multisample colour is resolved first and the temporal resolver then runs on the already-resolved buffer, so you pay for MSAA rasterisation on top of temporal supersampling that already anti-aliases the same edges.

    profile: boolean = false

    When true, measures per-segment GPU time (opaque/emissive/min-depth/tail/ composite/front/overlay) via timer queries and exposes it on timings. Adds a little CPU/driver overhead and lags a few frames, so it is off by default. No-op on platforms without EXT_disjoint_timer_query_webgl2.

    The most relevant figure for the transparent-geometry cost is OITRenderPassTimings.tail.

    resources: OITRenderPassResources = ...

    Resource/accumulation counters for leak monitoring, updated every render. See OITRenderPassResources.

    skipFront: boolean = false

    Debug: when true, the exact depth-peeled front layer is disabled and every transparent fragment is resolved through the weighted-blended (WBOIT) tail. Useful for isolating tail behaviour and comparing against the hybrid result.

    smaaQuality: SMAAQuality = 'high'

    SMAA quality preset used by the 'smaa' and 'temporal-smaa' antialias modes (default 'high'). Ignored by the other modes.

    stats: OITRenderPassStats = ...

    Per-frame object counts for each pass, updated every render. Useful for verifying which objects are routed through OIT vs. drawn opaque/overlay.

    timings: OITRenderPassTimings = ...

    Per-segment GPU timings (ms) from the last completed measurement. Only updated while profile is enabled. -1 means "no result yet" or unsupported.

    writeToScreen: boolean = false

    Accessors

    • get taaResolver(): TaaResolver | null

      The reprojected-TAA resolver, exposed for debug/tuning (e.g. its restClampStrength / restBoxGamma / restNeighbourhoodRadius anti-ghost knobs). Non-null only while antialias is 'taa' and after at least one frame has rendered (it is created lazily and recreated on a mode switch, resetting to defaults).

      Returns TaaResolver | null

    • get temporalResolver(): TemporalResolver | null

      The temporal-supersampling resolver, exposed for debug/tuning (e.g. its clampStrength anti-ghost knob). Non-null only while antialias is 'temporal' / 'temporal-smaa' and after at least one frame has rendered (it is created lazily and recreated on a mode switch, resetting to defaults).

      Returns TemporalResolver | null

    Methods