diff options
| author | yum <yum.food.vr@gmail.com> | 2026-01-14 14:31:13 -0800 |
|---|---|---|
| committer | yum <yum.food.vr@gmail.com> | 2026-01-14 14:34:28 -0800 |
| commit | 125f059267830d8f81694edb3ca83c6257f608f3 (patch) | |
| tree | cf6f040b75f0e63d45f3c4097e49d8dfc01f1c87 /index.md | |
| parent | 9f87b61fa59b5bd37d4539c8aeb6280963b7a69a (diff) | |
begin work on hemi octahedral article
Diffstat (limited to 'index.md')
| -rwxr-xr-x | index.md | 96 |
1 files changed, 96 insertions, 0 deletions
@@ -2,6 +2,102 @@ pagetitle: yummers lang: en --- +# hemi-octahedral impostors +14 Jan 2026 + +Ryan Brucks published [an +article](https://shaderbits.com/blog/octahedral-impostors) describing +"octahedral impostors" in 2018. The basic idea is to to take photos of some +subject at octahedral lattice points, record them to an atlas, then reconstruct +those photos in a particle. + + + +Why octahedrons? The octahedral mapping is simply one way to convert between a +flat coordinate system and a spherical coordinate system. It is notable because +it does not use any trig functions, making it suitable for use in realtime +graphics. + +This is what an octahedron looks like: + + + +It is a polyhedron with 8 triangular faces and 6 vertices. The equator is a +square. + +Let's work out how we'd convert this octahedron to a plane. +First, we project the upper hemisphere onto the xz plane: + + + +Next, we effectively need to "rotate" the triangles in the lower half around +those diagonal edges. We can cheat by first *reflecting* the bottom vertex of each +triangle about its diagonal edge: + + + +Finally, we can just project those points in the lower hemisphere onto the xz +plane: + + + +Viewed head on, we can see a very beautifully symmetric unwrapping: + + + +Note that we never actually did any rotations, so there's no trig! Here's the +same procedure in code: + +```c +// Convert unit octahedron to a [-1,1] x [-1,1] patch on xz plane. +float3 octahedron_to_plane(float3 p) { + if (p.y >= 0) { + // Project upper hemispher onto xz plane. + p.y = 0; + return p; + } + // First, reflect the lower hemisphere's points about their diagonal. + p.x = sign(p.x) * (1 - abs(p.x)); + p.z = sign(p.z) * (1 - abs(p.z)); + // Then project onto the xz plane. + p.y = 0; + return p; +} +``` + +We can generalize this procedure to unwrap *any* spherical object by just +switching norms: + +```c +// Convert unit sphere to a [-1,1] x [-1,1] patch on xz plane. +float3 octahedron_to_plane(float3 p) { + // Switch from L2 to L1 norm. This basically bends a sphere to an octahedron. + float l1_norm = abs(p.x) + abs(p.y) + abs(p.z); + p /= l1_norm; + // Then unwrap. + if (p.y >= 0) { + // Project upper hemispher onto xz plane. + p.y = 0; + return p; + } + // First, reflect the lower hemisphere's points about their diagonal. + p.x = sign(p.x) * (1 - abs(p.x)); + p.z = sign(p.z) * (1 - abs(p.z)); + // Then project onto the xz plane. + p.y = 0; + return p; +} +``` + +Here's a quick demo showing what that norm conversion does to a unit sphere: + + + +If you'd like more discussion on this topic, I recommend the spherical geometry section in [the PBR book](https://www.pbr-book.org/4ed/Geometry_and_Transformations/Spherical_Geometry#x3-OctahedralEncoding).) + # 6 wave dispersion relations with derivatives 21 Sep 2025 |
