#[derive(Debug, Clone)]
pub enum Skybox {
Solid([f32; 4]),
Gradient {
bottom: [f32; 3],
top: [f32; 3],
},
ThreeStop {
bottom: [f32; 3],
horizon: [f32; 3],
top: [f32; 3],
},
}
impl Default for Skybox {
fn default() -> Self {
Skybox::Solid([0.1, 0.1, 0.1, 1.0])
}
}
impl Skybox {
pub fn studio() -> Self {
Skybox::Gradient {
bottom: [0.15, 0.15, 0.18],
top: [0.05, 0.05, 0.08],
}
}
pub fn sky() -> Self {
Skybox::ThreeStop {
bottom: [0.4, 0.35, 0.3],
horizon: [0.7, 0.75, 0.85],
top: [0.3, 0.5, 0.9],
}
}
pub fn white() -> Self {
Skybox::Solid([1.0, 1.0, 1.0, 1.0])
}
pub fn black() -> Self {
Skybox::Solid([0.0, 0.0, 0.0, 1.0])
}
pub fn sample(&self, y: f32) -> [f32; 3] {
match self {
Skybox::Solid(c) => [c[0], c[1], c[2]],
Skybox::Gradient { bottom, top } => {
let t = y.clamp(0.0, 1.0);
[
bottom[0] + t * (top[0] - bottom[0]),
bottom[1] + t * (top[1] - bottom[1]),
bottom[2] + t * (top[2] - bottom[2]),
]
}
Skybox::ThreeStop { bottom, horizon, top } => {
let t = y.clamp(0.0, 1.0);
if t < 0.5 {
let s = t * 2.0;
[
bottom[0] + s * (horizon[0] - bottom[0]),
bottom[1] + s * (horizon[1] - bottom[1]),
bottom[2] + s * (horizon[2] - bottom[2]),
]
} else {
let s = (t - 0.5) * 2.0;
[
horizon[0] + s * (top[0] - horizon[0]),
horizon[1] + s * (top[1] - horizon[1]),
horizon[2] + s * (top[2] - horizon[2]),
]
}
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn solid() {
let sky = Skybox::Solid([0.5, 0.5, 0.5, 1.0]);
assert_eq!(sky.sample(0.0), [0.5, 0.5, 0.5]);
assert_eq!(sky.sample(1.0), [0.5, 0.5, 0.5]);
}
#[test]
fn gradient() {
let sky = Skybox::Gradient {
bottom: [0.0, 0.0, 0.0],
top: [1.0, 1.0, 1.0],
};
let mid = sky.sample(0.5);
assert!((mid[0] - 0.5).abs() < 1e-5);
}
#[test]
fn three_stop() {
let sky = Skybox::ThreeStop {
bottom: [0.0, 0.0, 0.0],
horizon: [0.5, 0.5, 0.5],
top: [1.0, 1.0, 1.0],
};
assert!((sky.sample(0.0)[0]).abs() < 1e-5);
assert!((sky.sample(0.5)[0] - 0.5).abs() < 1e-5);
assert!((sky.sample(1.0)[0] - 1.0).abs() < 1e-5);
}
#[test]
fn presets() {
let _ = Skybox::studio();
let _ = Skybox::sky();
let _ = Skybox::white();
let _ = Skybox::black();
}
}