Documentation
    Preparing search index...

    Class StencilState

    §57's stencil member: the stencil test a material's draws run under, and what they write back (§67).

    // Pass 1 — punch the mask. Writes 1 wherever this shape covers, and no colour.
    const write = new UnlitMaterial({
    color: [0, 0, 0, 0],
    colorWrite: false,
    depthWrite: false,
    stencil: { func: "always", ref: 1, passOp: "replace" },
    });

    // Pass 2 — draw only inside it. Tests, never writes.
    const inside = new UnlitMaterial({
    color: [0.9, 0.3, 0.2, 1],
    stencil: { func: "equal", ref: 1, writeMask: 0 },
    });

    A material that declares no stencil leaves the stencil test disabled, which is GL's initial state and the state every frame this engine drew before this class existed ran in. That is the byte-identity guarantee, and it is the property that let this land under the pixel-golden gate.

    new StencilState() is always/ref 0/0xff/0xff/keep/keep/keep — a stencil test that is enabled and passes everything, changing no stored value. It is a no-op with a cost, and that is the point: the only thing a bare StencilState changes is that enable(STENCIL_TEST) is issued, so a material that opts in and then names nothing gets the same picture, and every field it does name is the only thing that moved.

    Every property below is an accessor applying the same rule the constructor applies. The backend maps these names through a fixed table and passes the numbers to stencilFunc, stencilOp, and stencilMask; §61 forbids throwing inside a frame, so the assignment is where a bad value has to fail. A rejected write leaves the previous value in place.

    Mutating a StencilState does not announce anything to a material's version counter, for the reason §57's other render state does not: a backend reads render state per draw and caches none of it.

    Index
    • Builds the record, assigning through the accessors so one copy of each rule covers the option and every later write alike (the F14 discipline Material's constructor follows).

      Parameters

      Returns StencilState

    • get depthFailOp(): StencilOp

      What to store when the stencil test passes and the depth test fails; "keep" by default.

      The one worth stating: a mask pass usually runs with depthTest: false or depthWrite: false, because a mask that is occluded by the geometry it is masking would punch a hole in itself.

      Returns StencilOp

    • set depthFailOp(value: StencilOp): void

      Parameters

      Returns void

    • get failOp(): StencilOp

      What to store when the stencil test fails; "keep" by default.

      Returns StencilOp

    • set failOp(value: StencilOp): void

      Parameters

      Returns void

    • get func(): StencilFunc

      The comparison, "always" by default — see StencilFunc for the argument order (ref OP stored).

      Returns StencilFunc

    • set func(value: StencilFunc): void

      Parameters

      Returns void

    • get passOp(): StencilOp

      What to store when both tests pass; "keep" by default.

      Returns StencilOp

    • set passOp(value: StencilOp): void

      Parameters

      Returns void

    • get readMask(): number

      The bits of the reference and the stored value the test looks at; 0xff (all eight) by default.

      This is the bit-plane selector nested clipping needs: a clip that owns bit 2 tests with readMask: 0b100 and is blind to every other level's bits.

      Returns number

    • set readMask(value: number): void

      Parameters

      • value: number

      Returns void

    • get ref(): number

      The reference value the test compares and "replace" writes; 0 by default, an integer in 0…MAX_STENCIL_VALUE.

      Returns number

    • set ref(value: number): void

      Parameters

      • value: number

      Returns void

    • get writeMask(): number

      The bits a stencil write may change; 0xff by default, and 0 for the common "test but never write" material.

      A write mask of 0 makes StencilState.failOp, StencilState.depthFailOp, and StencilState.passOp inert — which is a legitimate way to say "read-only", and cheaper than setting all three to "keep", because it also protects against a later edit that changes one of them.

      Returns number

    • set writeMask(value: number): void

      Parameters

      • value: number

      Returns void

    • An independent copy. Materials share a StencilState by reference — like every other resource in §83's model — so this is how a caller derives a second pass from a first without editing the first.

      Returns StencilState