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}