Procedural fallback when no HDR is supplied. Warm horizon, cool zenith, faint sun — not physically correct, but better than a black background.
()
| 1539 | /// zenith, faint sun — not physically correct, but better than a |
| 1540 | /// black background. |
| 1541 | fn procedural() -> Self { |
| 1542 | // Build a tiny 256×128 equirect from a procedural formula so |
| 1543 | // the same sampling path works whether or not the user |
| 1544 | // supplied an .hdr. |
| 1545 | let w = 256u32; |
| 1546 | let h = 128u32; |
| 1547 | let sun_dir = Vec3::new(0.4, 0.8, 0.3).normalize(); |
| 1548 | let mut pixels = Vec::with_capacity((w * h) as usize); |
| 1549 | for y in 0..h { |
| 1550 | for x in 0..w { |
| 1551 | let u = (x as f32 + 0.5) / w as f32; |
| 1552 | let v = (y as f32 + 0.5) / h as f32; |
| 1553 | let theta = v * std::f32::consts::PI; // 0 at +Y, PI at -Y |
| 1554 | let phi = (u - 0.5) * 2.0 * std::f32::consts::PI; |
| 1555 | let dir = Vec3::new(theta.sin() * phi.cos(), theta.cos(), theta.sin() * phi.sin()); |
| 1556 | let horizon = Vec3::new(0.95, 0.85, 0.7); |
| 1557 | let zenith = Vec3::new(0.4, 0.55, 0.85); |
| 1558 | let sky = horizon.lerp(zenith, (0.5 * (dir.y + 1.0)).clamp(0.0, 1.0)); |
| 1559 | let sun = dir.dot(sun_dir).max(0.0).powf(512.0) * 8.0; |
| 1560 | pixels.push(sky * 1.2 + Vec3::splat(sun)); |
| 1561 | } |
| 1562 | } |
| 1563 | let distribution = EnvDistribution::build(&pixels, w, h); |
| 1564 | Self { |
| 1565 | pixels, |
| 1566 | width: w, |
| 1567 | height: h, |
| 1568 | intensity: 1.0, |
| 1569 | distribution, |
| 1570 | } |
| 1571 | } |
| 1572 | |
| 1573 | /// Sample the environment in a given direction. Uses the standard |
| 1574 | /// equirectangular convention: theta=0 at +Y (top), phi=0 at +Z, |