use std::f32::consts::PI;
use crate::hdr::HdrImage;
use crate::sample::sample_equirect;
const K0: f32 = 0.282_094_8; const K1: f32 = 0.488_602_5; const K2A: f32 = 1.092_548_4; const K2B: f32 = 0.315_391_6; const K2C: f32 = 0.546_274_2; const GOLDEN_ANGLE: f32 = 2.399_963_2;
pub fn project_sh9(env: &HdrImage, samples: u32) -> [[f32; 3]; 9] {
let mut sh = [[0.0f32; 3]; 9];
for i in 0..samples {
let y = 1.0 - 2.0 * (i as f32 + 0.5) / samples as f32;
let r = (1.0 - y * y).max(0.0).sqrt();
let phi = i as f32 * GOLDEN_ANGLE;
let dir = [r * phi.cos(), y, r * phi.sin()];
let rad = sample_equirect(&env.pixels, env.width, env.height, dir);
let [x, ny, z] = dir;
let basis: [f32; 9] = [
K0,
K1 * ny,
K1 * z,
K1 * x,
K2A * x * ny,
K2A * ny * z,
K2B * (3.0 * z * z - 1.0),
K2A * x * z,
K2C * (x * x - ny * ny),
];
for (c, &b) in basis.iter().enumerate() {
sh[c][0] += rad[0] * b;
sh[c][1] += rad[1] * b;
sh[c][2] += rad[2] * b;
}
}
let w = 4.0 * PI / samples as f32;
for coeff in &mut sh {
coeff[0] *= w;
coeff[1] *= w;
coeff[2] *= w;
}
sh
}
pub fn write_sh9_json(
path: &std::path::Path,
sh: &[[f32; 3]; 9],
) -> Result<(), crate::error::BakeError> {
let mut s = String::from("{\"sh9_coefficients\":[\n");
for (i, coeff) in sh.iter().enumerate() {
s.push_str(&format!(
" [{:.7},{:.7},{:.7}]",
coeff[0], coeff[1], coeff[2]
));
if i < 8 {
s.push(',');
}
s.push('\n');
}
s.push_str("]}\n");
std::fs::write(path, s.as_bytes())?;
Ok(())
}