Skip to main content

unity_formats/
shader.rs

1//! A Shader's render state as stored (`m_ParsedForm`): its subshaders, their passes and the passes' render-state
2//! values, with the `BlendMode` values they use. [`crate::material::ShaderData`] decodes them from a
3//! Shader object; [`procedural`] says which shaders build their geometry from component data.
4
5/// Whether a shader builds its geometry from component data, drawing a placeholder mesh: Shapes (a widely used
6/// package's line, disc, triangle and sphere shaders).
7pub fn procedural(shader: &str) -> bool {
8    shader.starts_with("Shapes/")
9}
10
11/// Unity's `BlendMode` values (`UnityEngine.Rendering.BlendMode`) a pass's blend factors use.
12pub mod blend_mode {
13    /// `Zero`.
14    pub const ZERO: u8 = 0;
15    /// `One`.
16    pub const ONE: u8 = 1;
17    /// `DstColor`.
18    pub const DST_COLOR: u8 = 2;
19    /// `SrcColor`.
20    pub const SRC_COLOR: u8 = 3;
21    /// `OneMinusDstColor`.
22    pub const ONE_MINUS_DST_COLOR: u8 = 4;
23    /// `SrcAlpha`.
24    pub const SRC_ALPHA: u8 = 5;
25    /// `OneMinusSrcColor`.
26    pub const ONE_MINUS_SRC_COLOR: u8 = 6;
27    /// `DstAlpha`.
28    pub const DST_ALPHA: u8 = 7;
29    /// `OneMinusDstAlpha`.
30    pub const ONE_MINUS_DST_ALPHA: u8 = 8;
31    /// `SrcAlphaSaturate`.
32    pub const SRC_ALPHA_SATURATE: u8 = 9;
33    /// `OneMinusSrcAlpha`.
34    pub const ONE_MINUS_SRC_ALPHA: u8 = 10;
35    /// The last value, `OneMinusSrcAlpha`.
36    pub const LAST: u8 = 10;
37}
38
39/// A render-state value of a shader pass: the value the shader declares, and the material property it is bound to
40/// (`Blend [_SrcBlend] ...`), which then gives the value.
41#[derive(Clone, Debug, PartialEq, serde::Serialize)]
42pub struct ShaderValue {
43    /// The value as stored.
44    pub value: f32,
45    /// The material property that gives the value instead, when the shader binds one (`None` for a fixed value).
46    pub property: Option<String>,
47}
48
49/// What a pass is (`m_Type`): one with its own state and programs, a `UsePass` naming another shader's pass
50/// (`m_UseName`, its state not here), or a `GrabPass` copying the screen to a texture (it draws nothing).
51#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize)]
52#[serde(rename_all = "snake_case")]
53pub enum PassKind {
54    /// A pass with its own state and programs.
55    Normal,
56    /// A `UsePass` of the named pass.
57    Use(String),
58    /// A `GrabPass`.
59    Grab,
60}
61
62/// One render target's blend and write mask as the pass states them (`rtBlend0` to `rtBlend7`): Unity's `BlendMode`
63/// factors and `BlendOp` operations, and the colour mask (bit 0 red to bit 3 alpha).
64#[derive(Clone, Debug, PartialEq, serde::Serialize)]
65pub struct ShaderTargetBlend {
66    /// `srcBlend`: the source colour factor.
67    pub src: ShaderValue,
68    /// `destBlend`: the destination colour factor.
69    pub dst: ShaderValue,
70    /// `srcBlendAlpha`: the source alpha factor.
71    pub src_alpha: ShaderValue,
72    /// `destBlendAlpha`: the destination alpha factor.
73    pub dst_alpha: ShaderValue,
74    /// `blendOp`: the colour operation.
75    pub op: ShaderValue,
76    /// `blendOpAlpha`: the alpha operation.
77    pub op_alpha: ShaderValue,
78    /// `colMask`: the colour write mask.
79    pub mask: ShaderValue,
80}
81
82/// A stencil face's operations (`SerializedStencilOp`): Unity's `StencilOp` for pass, fail and depth-fail, and its
83/// `CompareFunction` (0 disabled, 1 never, 2 less, 3 equal, 4 less or equal, 5 greater, 6 not equal, 7 greater or
84/// equal, 8 always).
85#[derive(Clone, Debug, PartialEq, serde::Serialize)]
86pub struct ShaderStencilOp {
87    /// The operation when the stencil and depth tests pass.
88    pub pass: ShaderValue,
89    /// The operation when the stencil test fails.
90    pub fail: ShaderValue,
91    /// The operation when the depth test fails.
92    pub z_fail: ShaderValue,
93    /// The stencil comparison.
94    pub comp: ShaderValue,
95}
96
97/// The rest of a pass's render state as stored (`m_State`): every render target's blend, the depth test and offset and
98/// the stencil.
99#[derive(Clone, Debug, PartialEq, serde::Serialize)]
100pub struct PassState {
101    /// `rtBlend0` to `rtBlend7`; the first is the pass's `src_blend` and `dst_blend`.
102    pub targets: Vec<ShaderTargetBlend>,
103    /// `rtSeparateBlend`: whether targets 1 to 7 state their own blend (else they take target 0's).
104    pub separate_blend: bool,
105    /// `zTest`, a `CompareFunction`.
106    pub z_test: ShaderValue,
107    /// `Offset factor, units`.
108    pub offset_factor: ShaderValue,
109    /// `Offset factor, units`: the units.
110    pub offset_units: ShaderValue,
111    /// `stencilRef`, `stencilReadMask`, `stencilWriteMask`.
112    pub stencil_ref: ShaderValue,
113    /// `stencilReadMask`.
114    pub stencil_read_mask: ShaderValue,
115    /// `stencilWriteMask`.
116    pub stencil_write_mask: ShaderValue,
117    /// `stencilOp`, `stencilOpFront`, `stencilOpBack`.
118    pub stencil_op: ShaderStencilOp,
119    /// `stencilOpFront`.
120    pub stencil_op_front: ShaderStencilOp,
121    /// `stencilOpBack`.
122    pub stencil_op_back: ShaderStencilOp,
123}
124
125/// A shader pass's kind and render state: its `LightMode` tag as stored (Unity upper-cases some: `FORWARDBASE`), the
126/// first render target's blend factors (Unity's `BlendMode`, [`blend_mode`]: 0 Zero, 1 One, 5 SrcAlpha, 10 OneMinusSrcAlpha, ...),
127/// depth writes and culling (0 off, 1 front, 2 back).
128#[derive(Clone, Debug, PartialEq, serde::Serialize)]
129pub struct ShaderPass {
130    /// What the pass is.
131    pub kind: PassKind,
132    /// The pass's `LightMode` tag as stored; `None` when it has none.
133    pub light_mode: Option<String>,
134    /// `srcBlend` of the first render target.
135    pub src_blend: ShaderValue,
136    /// `destBlend` of the first render target.
137    pub dst_blend: ShaderValue,
138    /// `zWrite`: whether the pass writes depth.
139    pub zwrite: ShaderValue,
140    /// `culling`: which faces are culled.
141    pub cull: ShaderValue,
142    /// The rest of the pass's render state.
143    pub state: PassState,
144}
145
146/// A subshader: its tags as stored (Unity upper-cases some keys: `QUEUE`) and its passes in order.
147#[derive(Clone, Debug, PartialEq, serde::Serialize)]
148pub struct SubShader {
149    /// The subshader's tags.
150    pub tags: Vec<(String, String)>,
151    /// The passes, in order.
152    pub passes: Vec<ShaderPass>,
153}
154
155#[cfg(test)]
156mod tests {
157    use super::blend_mode::*;
158
159    /// Every `BlendMode` value from 0 to [`LAST`] has a constant, in the order Unity declares them.
160    #[test]
161    fn blend_modes_cover_unitys_eleven_values() {
162        let all = [
163            ZERO,
164            ONE,
165            DST_COLOR,
166            SRC_COLOR,
167            ONE_MINUS_DST_COLOR,
168            SRC_ALPHA,
169            ONE_MINUS_SRC_COLOR,
170            DST_ALPHA,
171            ONE_MINUS_DST_ALPHA,
172            SRC_ALPHA_SATURATE,
173            ONE_MINUS_SRC_ALPHA,
174        ];
175        assert_eq!(all, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
176        assert_eq!(usize::from(LAST) + 1, all.len());
177    }
178}