///|
/// Advanced sampling strategies for Monte Carlo integration.
/// Includes stratified sampling, MIS heuristics, and pixel filters.
pub fn sobol_sample(_index : Int, _dimension : Int) -> Double {
0.5
}
pub fn stratified_2d(s : Int, t : Int, nx : Int, ny : Int) -> (Double, Double) {
let rng = new_rng((s * 1973 + t * 2663).to_uint64())
let (dx, r1) = rng.random_double()
let (dy, _) = r1.random_double()
((s.to_double() + dx) / nx.to_double(), (t.to_double() + dy) / ny.to_double())
}
pub fn tent_filter(x : Double) -> Double {
if x < 1.0 {
1.0 - x.abs()
} else {
0.0
}
}
pub fn gaussian_filter(x : Double, sigma : Double) -> Double {
let inv_sigma = 1.0 / sigma
@math.exp(-0.5 * x * x * inv_sigma * inv_sigma)
}
pub fn balanced_heuristic(n_f : Double, pdf_f : Double, n_g : Double, pdf_g : Double) -> Double {
let f = n_f * pdf_f
let g = n_g * pdf_g
f / (f + g)
}
pub fn power_heuristic(n_f : Double, pdf_f : Double, n_g : Double, pdf_g : Double, beta~ : Double) -> Double {
let f = n_f * @math.pow(pdf_f, beta)
let g = n_g * @math.pow(pdf_g, beta)
f / (f + g)
}
pub fn uniform_sample_hemisphere(rng : Rng, normal : Vec3) -> (Vec3, Rng, Double) {
let (xi1, r1) = rng.random_double()
let (xi2, r2) = r1.random_double()
let z = xi1
let r = (1.0 - z * z).max(0.0).sqrt()
let phi = 2.0 * @math.PI * xi2
let dir = { x: r * @math.cos(phi), y: r * @math.sin(phi), z }
let onb = ONB::build_from_w(normal=normal)
let world_dir = onb.local_vec(dir.x, dir.y, dir.z)
let pdf = 1.0 / (2.0 * @math.PI)
(world_dir, r2, pdf)
}
pub fn uniform_sample_sphere(rng : Rng) -> (Vec3, Rng) {
let (xi1, r1) = rng.random_double()
let (xi2, r2) = r1.random_double()
let z = 1.0 - 2.0 * xi1
let r = (1.0 - z * z).max(0.0).sqrt()
let phi = 2.0 * @math.PI * xi2
({ x: r * @math.cos(phi), y: r * @math.sin(phi), z }, r2)
}
pub fn uniform_cone_pdf(cos_theta_max : Double) -> Double {
1.0 / (2.0 * @math.PI * (1.0 - cos_theta_max))
}
pub fn uniform_sample_cone(rng : Rng, cos_theta_max : Double) -> (Vec3, Rng) {
let (xi1, r1) = rng.random_double()
let (xi2, r2) = r1.random_double()
let cos_theta = (1.0 - xi1) + xi1 * cos_theta_max
let sin_theta = (1.0 - cos_theta * cos_theta).max(0.0).sqrt()
let phi = 2.0 * @math.PI * xi2
({ x: @math.cos(phi) * sin_theta, y: @math.sin(phi) * sin_theta, z: cos_theta }, r2)
}
pub fn uniform_cone_sample_with_base(rng : Rng, w : Vec3, cos_theta_max : Double) -> (Vec3, Rng) {
let (dir, new_rng) = uniform_sample_cone(rng, cos_theta_max)
let onb = ONB::build_from_w(normal=w)
(onb.local_vec(dir.x, dir.y, dir.z), new_rng)
}