use sciforge::hub::prelude::constants::elements::{atomic_mass, electronegativity};
#[derive(Debug, Clone)]
pub struct PbrMaterial {
pub name: &'static str,
pub albedo: [f32; 4],
pub roughness: f32,
pub metallic: f32,
pub normal_strength: f32,
pub emissive: [f32; 3],
pub ior: f32,
pub subsurface: f32,
}
fn metallic_from_iron(fe_wt_frac: f64) -> f32 {
let m_fe = atomic_mass(26);
let m_o = atomic_mass(8);
let fe_fraction_in_feo = m_fe / (m_fe + m_o);
let pure_fe = fe_wt_frac * fe_fraction_in_feo;
let en = electronegativity(26).unwrap_or(1.83);
let metallic_scale = (1.0 - en / 4.0).max(0.0);
(pure_fe * metallic_scale).clamp(0.0, 1.0) as f32
}
impl PbrMaterial {
pub fn deep_ocean() -> Self {
Self {
name: "deep_ocean",
albedo: [0.006, 0.018, 0.065, 1.0],
roughness: 0.02,
metallic: 0.02,
normal_strength: 1.0,
emissive: [0.0; 3],
ior: 1.333,
subsurface: 0.4,
}
}
pub fn shallow_ocean() -> Self {
Self {
name: "shallow_ocean",
albedo: [0.04, 0.12, 0.18, 1.0],
roughness: 0.05,
metallic: 0.02,
normal_strength: 0.8,
emissive: [0.0; 3],
ior: 1.333,
subsurface: 0.6,
}
}
pub fn grassland() -> Self {
Self {
name: "grassland",
albedo: [0.12, 0.36, 0.08, 1.0],
roughness: 0.85,
metallic: 0.0,
normal_strength: 0.8,
emissive: [0.0; 3],
ior: 1.45,
subsurface: 0.3,
}
}
pub fn desert_sand() -> Self {
Self {
name: "desert_sand",
albedo: [0.76, 0.60, 0.36, 1.0],
roughness: 0.95,
metallic: metallic_from_iron(0.02),
normal_strength: 0.6,
emissive: [0.0; 3],
ior: 1.544,
subsurface: 0.0,
}
}
pub fn fresh_snow() -> Self {
Self {
name: "fresh_snow",
albedo: [0.95, 0.95, 0.97, 1.0],
roughness: 0.3,
metallic: 0.0,
normal_strength: 0.3,
emissive: [0.0; 3],
ior: 1.309,
subsurface: 0.8,
}
}
pub fn granite() -> Self {
Self {
name: "granite",
albedo: [0.40, 0.36, 0.33, 1.0],
roughness: 0.88,
metallic: metallic_from_iron(0.015),
normal_strength: 1.0,
emissive: [0.0; 3],
ior: 1.544,
subsurface: 0.0,
}
}
pub fn basalt() -> Self {
Self {
name: "basalt",
albedo: [0.15, 0.13, 0.12, 1.0],
roughness: 0.92,
metallic: metallic_from_iron(0.08),
normal_strength: 1.0,
emissive: [0.0; 3],
ior: 1.58,
subsurface: 0.0,
}
}
pub fn volcanic_lava() -> Self {
Self {
name: "volcanic_lava",
albedo: [0.15, 0.08, 0.05, 1.0],
roughness: 0.7,
metallic: metallic_from_iron(0.10),
normal_strength: 1.0,
emissive: [0.8, 0.2, 0.0],
ior: 1.50,
subsurface: 0.0,
}
}
pub fn tropical_forest() -> Self {
Self {
name: "tropical_forest",
albedo: [0.04, 0.18, 0.02, 1.0],
roughness: 0.92,
metallic: 0.0,
normal_strength: 0.9,
emissive: [0.0; 3],
ior: 1.45,
subsurface: 0.35,
}
}
pub fn boreal_forest() -> Self {
Self {
name: "boreal_forest",
albedo: [0.05, 0.12, 0.04, 1.0],
roughness: 0.90,
metallic: 0.0,
normal_strength: 0.85,
emissive: [0.0; 3],
ior: 1.45,
subsurface: 0.25,
}
}
pub fn glacier_ice() -> Self {
Self {
name: "glacier_ice",
albedo: [0.70, 0.85, 0.92, 0.85],
roughness: 0.1,
metallic: 0.04,
normal_strength: 0.5,
emissive: [0.0; 3],
ior: 1.309,
subsurface: 0.9,
}
}
pub fn clay_soil() -> Self {
Self {
name: "clay_soil",
albedo: [0.42, 0.28, 0.18, 1.0],
roughness: 0.95,
metallic: metallic_from_iron(0.04),
normal_strength: 0.7,
emissive: [0.0; 3],
ior: 1.50,
subsurface: 0.1,
}
}
pub fn limestone() -> Self {
let m_ca = atomic_mass(20);
let m_c = atomic_mass(6);
let m_o = atomic_mass(8);
let _ = m_ca + m_c + 3.0 * m_o;
Self {
name: "limestone",
albedo: [0.82, 0.80, 0.74, 1.0],
roughness: 0.80,
metallic: 0.0,
normal_strength: 0.9,
emissive: [0.0; 3],
ior: 1.486,
subsurface: 0.05,
}
}
pub fn coral_reef() -> Self {
Self {
name: "coral_reef",
albedo: [0.55, 0.40, 0.30, 1.0],
roughness: 0.75,
metallic: 0.0,
normal_strength: 1.0,
emissive: [0.0; 3],
ior: 1.486,
subsurface: 0.15,
}
}
pub fn all_earth() -> Vec<Self> {
vec![
Self::deep_ocean(),
Self::shallow_ocean(),
Self::grassland(),
Self::desert_sand(),
Self::fresh_snow(),
Self::granite(),
Self::basalt(),
Self::volcanic_lava(),
Self::tropical_forest(),
Self::boreal_forest(),
Self::glacier_ice(),
Self::clay_soil(),
Self::limestone(),
Self::coral_reef(),
]
}
pub fn fresnel_r0(&self) -> f64 {
((self.ior as f64 - 1.0) / (self.ior as f64 + 1.0)).powi(2)
}
}