Home - Blog - 2020-05-05

Sometime in late spring or early summer 2019,
one of my friends wanted a widget on their website:

"a rotating shape, like an icosahedron,
with a sort of iridescent effect to it."
- paraphrased from memory

I was immediately inspired, and in ten minutes
I made a satisfactory demo in Blender. [1]

The hard part was actually making the widget.
It was my first-ever time writing javascript. [2]

Fortunately, basic javascript isn't particularly hard.
A different friend, who was actually writing the website,
directed me to the three.js library for graphics legwork.
This made it pretty easy to create an icosahedron,
make it wobble a bit, and cover it with a custom shader.

Writing the shader dredged up memories
of the one OpenGL class I took years ago. [3]
I had to look everything up, but it was all half-familiar,
and certainly easier than doing it for the first time.

Since my friend's expectations were vague,
I devised a very... crude iridescence shader.

"Iridescence" is when the color of an object
changes when viewed from different angles.

My implementation just takes the XYZ location
of each pixel's worth of surface, or "fragment".
To this, it adds the difference between:

The geometric-nonsense result
is the fragment's RGB color.

gl_FragColor = vec4(
  location+vec3(1.5)*(faceNormal-location),
  1.0 // alpha channel -- fully opaque
);

This worked well because on sphere-like objects
like the icosahedron, the location of a fragment
closely corresponds to its angle to the viewer. [4]

Gently rotate the icosahedron, and the location
(and color) of its surfaces smoothly changes.
The effect satisfied me and also my friends.

Looking to identify the shader as
a cheap [5] imitation of the real thing,
I named it "Tin Iridescence".


By this point I had gotten deeply involved
in the project, so I ended up pair-programming
the whole website with my friends. [6]

They learned a lot about 3D graphics
(we wrote Voronoi cells from scratch)
and I learned a lot about JS and CSS. [7]

We wrote two completely different ways
to make the icosahedron spin around,
and stuck with the easier-to-keep-right one.

The final result was "Invisible Networks".
The source code is on GitHub.


[1] As previously evidenced,
Blender is a favorite tool of mine.

[2] Actually, I had written one line of JS before:
a redirect prank on a friend's toy wiki engine
to show why the inputs needed to be sanitized.

[3] That was a really weird class.
We wrote OpenGL shaders as fullscreen iOS apps.
The apps were written in this hot new language
called "Swift", which wasn't very stable at the time,
and required Xcode on an Apple computer to compile.
We ran the apps on our iOS devices or, for those of
us who didn't have one, Apple's development emulator.
It was one of the weirder toolchains I used in school.

[4] The shader only works well on sherical objects.
A more general shader might compute the "normal"
("the direction it's facing") of every fragment
relative to the camera, rather than globally,
and use some more sophisticated function
to derive color from location and normal.

[5] Cheap in the both the sense of
"inexpensive" and of "low-quality".

[6] This was actually really fun to pair-program.
I'm not sure why it was better than in school.

Maybe because there were no grades or deadlines,
or because we were friends and already got along,
or because we were trading knowledge back and forth.

Definitely an experience I would wish on other people.

[7] I either learned too much or too little
about CSS to (want to) use it.

The one style rule my website has
was written by this same friend.