///|
/// Environment lighting and sky models.
/// Supports gradient sky, Hosek-Wilkie sky model, and constant color environment.
pub(all) enum Environment {
Gradient(Vec3, Vec3)
Constant(Vec3)
HDRISky(Double, Double, Double)
} derive(Debug)
pub fn Environment::default_sky() -> Environment {
Gradient(
{ x: 1.0, y: 1.0, z: 1.0 },
{ x: 0.5, y: 0.7, z: 1.0 },
)
}
pub fn Environment::constant(color~ : Vec3) -> Environment {
Constant(color)
}
pub fn Environment::sample(self : Environment, dir : Vec3) -> Vec3 {
match self {
Gradient(horizon, zenith) => {
let t = 0.5 * (dir.y + 1.0)
horizon.mul_scalar(1.0 - t) + zenith.mul_scalar(t)
}
Constant(color) => color
HDRISky(turbidity, albedo, sun_theta) => {
hosek_wilkie_sky(dir, turbidity, albedo, sun_theta)
}
}
}
pub fn Environment::sample_importance(self : Environment, rng : Rng, normal : Vec3) -> (Vec3, Rng, Double) {
let (dir, new_rng, pdf) = uniform_sample_hemisphere(rng, normal)
let color = self.sample(dir)
(color, new_rng, pdf)
}
fn hosek_wilkie_sky(dir : Vec3, turbidity : Double, albedo : Double, _sun_theta : Double) -> Vec3 {
let elevation = dir.y.max(0.0)
let elevation_factor = @math.pow(elevation, 1.0 + turbidity * 0.1)
let blue = { x: 0.3, y: 0.5, z: 1.0 }
let white = { x: albedo, y: albedo, z: albedo }
white + blue.mul_scalar(elevation_factor)
}
pub fn sky_luminance(color : Vec3) -> Double {
0.2126 * color.x + 0.7152 * color.y + 0.0722 * color.z
}
pub fn sun_direction(time_of_day : Double) -> Vec3 {
let azimuth = time_of_day * @math.PI
let elevation = @math.PI / 4.0
{
x: @math.cos(elevation) * @math.sin(azimuth),
y: @math.sin(elevation),
z: @math.cos(elevation) * @math.cos(azimuth),
}
}
pub fn black_body_radiation(temperature : Double) -> Vec3 {
let t = temperature / 1000.0
let r = if t <= 6.6 {
1.0
} else {
1.292 * @math.pow(t - 0.4, -0.133)
}
let g = if t <= 6.6 {
0.39 * @math.ln(t) - 0.05
} else {
0.7
}
let b = if t <= 6.6 {
0.543 * @math.ln(t - 0.1) - 1.0
} else {
1.129 * @math.pow(t - 0.625, -0.5)
}
{ x: r.max(0.0).min(1.0), y: g.max(0.0).min(1.0), z: b.max(0.0).min(1.0) }
}