Skip to main content

scenix_material/
normal.rs

1use crate::traits::double_sided_bit;
2use crate::{
3    AlphaMode, FEATURE_FLAT_SHADING, FEATURE_WORLD_SPACE, Material, PipelineAlphaMode, PipelineKey,
4    ShaderKind,
5};
6
7/// Debug material that renders surface normals as RGB colors.
8#[derive(Clone, Copy, Debug, PartialEq)]
9#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
10pub struct NormalMaterial {
11    /// Output opacity.
12    pub opacity: f32,
13    /// Whether to use flat face normals.
14    pub flat_shading: bool,
15    /// Whether normals are displayed in world space instead of view space.
16    pub world_space: bool,
17    /// Whether the material is rendered double-sided.
18    pub double_sided: bool,
19}
20
21impl NormalMaterial {
22    /// Creates a default normal debug material.
23    #[inline]
24    pub const fn new() -> Self {
25        Self {
26            opacity: 1.0,
27            flat_shading: false,
28            world_space: false,
29            double_sided: false,
30        }
31    }
32
33    /// Returns this material with opacity.
34    #[inline]
35    pub fn opacity(mut self, opacity: f32) -> Self {
36        self.opacity = opacity.clamp(0.0, 1.0);
37        self
38    }
39}
40
41impl Default for NormalMaterial {
42    #[inline]
43    fn default() -> Self {
44        Self::new()
45    }
46}
47
48impl Material for NormalMaterial {
49    #[inline]
50    fn pipeline_key(&self) -> PipelineKey {
51        let mut bits = double_sided_bit(self.double_sided);
52        if self.flat_shading {
53            bits |= FEATURE_FLAT_SHADING;
54        }
55        if self.world_space {
56            bits |= FEATURE_WORLD_SPACE;
57        }
58        let alpha = if self.opacity < 1.0 {
59            PipelineAlphaMode::Blend
60        } else {
61            PipelineAlphaMode::Opaque
62        };
63        PipelineKey::new(ShaderKind::Normal, alpha, bits)
64    }
65
66    #[inline]
67    fn is_transparent(&self) -> bool {
68        self.opacity < 1.0
69    }
70
71    #[inline]
72    fn double_sided(&self) -> bool {
73        self.double_sided
74    }
75
76    #[inline]
77    fn alpha_cutoff(&self) -> Option<f32> {
78        AlphaMode::Opaque.cutoff()
79    }
80}