#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ParamVisMode {
Checker = 1,
Grid = 2,
LocalChecker = 3,
LocalRadial = 4,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct ParamVis {
pub mode: ParamVisMode,
pub scale: f32,
}
impl Default for ParamVis {
fn default() -> Self {
Self {
mode: ParamVisMode::Checker,
scale: 8.0,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BackfacePattern {
Checker = 0,
Hatching = 1,
Crosshatch = 2,
Stripes = 3,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct PatternConfig {
pub pattern: BackfacePattern,
pub color: [f32; 3],
pub scale: f32,
}
impl Default for PatternConfig {
fn default() -> Self {
Self {
pattern: BackfacePattern::Checker,
color: [1.0, 0.5, 0.0],
scale: 20.0,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum BackfacePolicy {
Cull,
Identical,
DifferentColor([f32; 3]),
Tint(f32),
Pattern(PatternConfig),
}
impl Default for BackfacePolicy {
fn default() -> Self {
BackfacePolicy::Cull
}
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Material {
pub base_color: [f32; 3],
pub ambient: f32,
pub diffuse: f32,
pub specular: f32,
pub shininess: f32,
pub metallic: f32,
pub roughness: f32,
pub opacity: f32,
pub texture_id: Option<u64>,
pub normal_map_id: Option<u64>,
pub ao_map_id: Option<u64>,
pub use_pbr: bool,
pub matcap_id: Option<crate::resources::MatcapId>,
pub param_vis: Option<ParamVis>,
pub backface_policy: BackfacePolicy,
}
impl Default for Material {
fn default() -> Self {
Self {
base_color: [0.7, 0.7, 0.7],
ambient: 0.15,
diffuse: 0.75,
specular: 0.4,
shininess: 32.0,
metallic: 0.0,
roughness: 0.5,
opacity: 1.0,
texture_id: None,
normal_map_id: None,
ao_map_id: None,
use_pbr: false,
matcap_id: None,
param_vis: None,
backface_policy: BackfacePolicy::Cull,
}
}
}
impl Material {
pub fn is_two_sided(&self) -> bool {
!matches!(self.backface_policy, BackfacePolicy::Cull)
}
pub fn from_color(color: [f32; 3]) -> Self {
Self {
base_color: color,
..Default::default()
}
}
pub fn pbr(base_color: [f32; 3], metallic: f32, roughness: f32) -> Self {
Self {
base_color,
use_pbr: true,
metallic,
roughness,
..Default::default()
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn default_values() {
let m = Material::default();
assert!((m.base_color[0] - 0.7).abs() < 1e-6);
assert!((m.ambient - 0.15).abs() < 1e-6);
assert!((m.diffuse - 0.75).abs() < 1e-6);
assert!((m.opacity - 1.0).abs() < 1e-6);
assert!(!m.use_pbr);
assert!(m.texture_id.is_none());
assert!(m.normal_map_id.is_none());
assert!(m.ao_map_id.is_none());
assert!(m.matcap_id.is_none());
assert!(m.param_vis.is_none());
}
#[test]
fn from_color_sets_base_color() {
let m = Material::from_color([1.0, 0.0, 0.5]);
assert!((m.base_color[0] - 1.0).abs() < 1e-6);
assert!((m.base_color[1]).abs() < 1e-6);
assert!((m.base_color[2] - 0.5).abs() < 1e-6);
assert!((m.ambient - 0.15).abs() < 1e-6);
}
#[test]
fn pbr_constructor() {
let m = Material::pbr([0.8, 0.2, 0.1], 0.9, 0.3);
assert!(m.use_pbr);
assert!((m.metallic - 0.9).abs() < 1e-6);
assert!((m.roughness - 0.3).abs() < 1e-6);
assert!((m.base_color[0] - 0.8).abs() < 1e-6);
}
#[test]
fn is_two_sided_cull() {
let m = Material::default();
assert!(!m.is_two_sided());
}
#[test]
fn is_two_sided_identical() {
let m = Material {
backface_policy: BackfacePolicy::Identical,
..Default::default()
};
assert!(m.is_two_sided());
}
#[test]
fn is_two_sided_different_color() {
let m = Material {
backface_policy: BackfacePolicy::DifferentColor([1.0, 0.0, 0.0]),
..Default::default()
};
assert!(m.is_two_sided());
}
#[test]
fn is_two_sided_tint() {
let m = Material {
backface_policy: BackfacePolicy::Tint(0.3),
..Default::default()
};
assert!(m.is_two_sided());
}
#[test]
fn is_two_sided_pattern() {
let m = Material {
backface_policy: BackfacePolicy::Pattern(PatternConfig {
pattern: BackfacePattern::Hatching,
color: [0.5, 0.5, 0.5],
..Default::default()
}),
..Default::default()
};
assert!(m.is_two_sided());
}
#[test]
fn param_vis_default() {
let pv = ParamVis::default();
assert_eq!(pv.mode, ParamVisMode::Checker);
assert!((pv.scale - 8.0).abs() < 1e-6);
}
}