1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
//! Shader cache key for the **masked** (alpha-tested) variant of the
//! shadow-generation pass — the B2 hole-shaped-shadow path.
//!
//! A glTF `alphaMode = MASK` caster must cast a *cutout* shadow: fragments
//! below the cutoff are `discard`ed so the hole doesn't write shadow depth and
//! later depth-tested receivers see light through it. The plain shadow pass is
//! depth-only with no fragment; this masked variant adds a fragment that
//! reconstructs the masking alpha (base-color × factor, or the custom material's
//! alpha-only WGSL) and discards below `MaterialMeshMeta.alpha_cutoff`.
//!
//! Specialized per `shader_id` for the same reason as the masked geometry
//! variant: the template can't pull the full `materials_wgsl` blob (opaque-only
//! contract types). Built-in PBR / Unlit / Toon share the base-color path; a
//! dynamic (custom) material emits the author's alpha-only fragment.
//!
//! Reuses [`DynamicAlphaShaderInfo`] from the masked geometry variant so a
//! custom material's alpha-only window is wrapped identically in both passes.
//! The cutout alpha logic itself lives in `shared_wgsl/masked_alpha.wgsl`,
//! included by both fragments.
//!
//! The shadow atlas is single-sampled, so there is no MSAA / `sample_mask`
//! field (binary discard; PCF/PCSS softens the edge). The variant DOES fork by
//! `instancing_transforms` (the shadow pass draws instanced casters), which
//! selects the storage-array vs uniform-with-dynamic-offset meta binding —
//! matching the plain shadow pipeline's two layouts.
use MaterialShaderId;
use crate::;
/// Cache key for the masked shadow-generation shader.