Sample the environment in a given direction. Uses the standard equirectangular convention: theta=0 at +Y (top), phi=0 at +Z, phi rotating toward +X. Bilinear-filtered.
(&self, direction: Vec3)
| 1574 | /// equirectangular convention: theta=0 at +Y (top), phi=0 at +Z, |
| 1575 | /// phi rotating toward +X. Bilinear-filtered. |
| 1576 | fn sample(&self, direction: Vec3) -> Vec3 { |
| 1577 | let d = direction.normalize_or_zero(); |
| 1578 | let theta = d.y.clamp(-1.0, 1.0).acos(); |
| 1579 | let phi = d.z.atan2(d.x); |
| 1580 | let u = (phi / (2.0 * std::f32::consts::PI)).rem_euclid(1.0); |
| 1581 | let v = (theta / std::f32::consts::PI).clamp(0.0, 1.0); |
| 1582 | |
| 1583 | let fx = u * self.width as f32 - 0.5; |
| 1584 | let fy = v * self.height as f32 - 0.5; |
| 1585 | let x0 = fx.floor() as i32; |
| 1586 | let y0 = fy.floor() as i32; |
| 1587 | let tx = fx - x0 as f32; |
| 1588 | let ty = fy - y0 as f32; |
| 1589 | |
| 1590 | let w = self.width as i32; |
| 1591 | let h = self.height as i32; |
| 1592 | let fetch = |x: i32, y: i32| -> Vec3 { |
| 1593 | let xc = x.rem_euclid(w) as usize; |
| 1594 | let yc = y.clamp(0, h - 1) as usize; |
| 1595 | self.pixels[yc * self.width as usize + xc] |
| 1596 | }; |
| 1597 | let c00 = fetch(x0, y0); |
| 1598 | let c10 = fetch(x0 + 1, y0); |
| 1599 | let c01 = fetch(x0, y0 + 1); |
| 1600 | let c11 = fetch(x0 + 1, y0 + 1); |
| 1601 | c00.lerp(c10, tx).lerp(c01.lerp(c11, tx), ty) * self.intensity |
| 1602 | } |
| 1603 | |
| 1604 | /// Convert a pixel (column, row) to a world-space direction. The |
| 1605 | /// sample lands at the pixel center. Returns the direction |
no outgoing calls
no test coverage detected