summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoryum <yum.food.vr@gmail.com>2026-01-14 14:31:13 -0800
committeryum <yum.food.vr@gmail.com>2026-01-14 14:34:28 -0800
commit125f059267830d8f81694edb3ca83c6257f608f3 (patch)
treecf6f040b75f0e63d45f3c4097e49d8dfc01f1c87
parent9f87b61fa59b5bd37d4539c8aeb6280963b7a69a (diff)
begin work on hemi octahedral article
-rwxr-xr-xindex.md96
-rwxr-xr-xmake_html2
-rwxr-xr-xtemplate.html2
3 files changed, 99 insertions, 1 deletions
diff --git a/index.md b/index.md
index 1164d51..592b993 100755
--- a/index.md
+++ b/index.md
@@ -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.
+
+![Octahedral lattice points around some object.](./images/2026_01_14/Screenshot from 2026-01-14
+13-35-40.png)
+
+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:
+
+![Unit octahedron.](./images/2026_01_14/Screenshot from 2026-01-14
+13-54-05.png)
+
+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:
+
+![Octahedron with upper hemisphere projected onto xz
+plane.](./images/2026_01_14/Screenshot from 2026-01-14 13-50-27.png)
+
+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:
+
+![Octahedron with reflected lower hemisphere.](./images/2026_01_14/Screenshot from 2026-01-14 13-58-18.png)
+
+Finally, we can just project those points in the lower hemisphere onto the xz
+plane:
+
+![Fully unwrapped octahedron.](./images/2026_01_14/Screenshot from 2026-01-14 13-59-24.png)
+
+Viewed head on, we can see a very beautifully symmetric unwrapping:
+
+![Unwrapped octahedron, head on.](./images/2026_01_14/Screenshot from 2026-01-14 14-00-16.png)
+
+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:
+
+![Converting a sphere to an octahedron via norm conversion.](./images/2026_01_14/hemi_octahedral_04.mp4)
+
+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
diff --git a/make_html b/make_html
index e021eb5..ec4d16d 100755
--- a/make_html
+++ b/make_html
@@ -23,7 +23,7 @@ pandoc \
unzip -o "$OUTPUT_DIR/site.zip" -d /var/www/html/
# Remove in-page hash fragments from TOC links on the landing page so links open at page top
-sed -E -i 's/(href="[^"#]+\.html)#[^"]+"/\1"/g' /var/www/html/index.html
+sed -E -i 's/(href="[^"#]+\.html)#[^"]+"/\1"/g' /var/www/html/index.html || true
cp -r vr_assets /var/www/html/
cp -r images /var/www/html/
diff --git a/template.html b/template.html
index ae3cd6a..173fb82 100755
--- a/template.html
+++ b/template.html
@@ -34,6 +34,7 @@ $endif$
math {
font-family: "Cambria Math", "Latin Modern Math", "STIX Two Math", serif;
}
+ video { max-width: 100%; height: auto; }
@media (prefers-color-scheme: dark) {
/* Tomorrow night theme: https://github.com/chriskempson/tomorrow-theme */
:root {
@@ -72,6 +73,7 @@ $endif$
html, body {
background-color: var(--background-color);
color: var(--foreground-color);
+ padding-left: 1em;
}
a { color: var(--foreground-color); }
a:visited { color: var(--foreground-color); }