Released at Nova 2020, 4KB Executable Graphics (a single 4KB executable file generates this image, with no external data) with help from Lia-Sae.
The challenge: Rendering realistic cloth
I was thinking a lot about materials before I started this, particularly how texture isn’t really a thing when you look close enough: there’s only geometry and material. Texture is how we perceive fine surface details.
It follows, then, that realistic rendering should use ultra-detailed geometry, not textures.
I decided to try it, by rendering cloth 🤦♀️
To give the scene some scale, I had to show cloth up close. That ended up being difficult - how to show it nicely and give it scale? I decided to make tiny cloth flags and carpet, and use Lego to give it a sense of scale.
I started with the lighting. The ambient light has a blue tint and the main light yellow to indicate daytime / sunlight. To provide a visual cue that we’re indoors I added some shadows across the scene, perhaps the wooden frame between window panes.
Getting the lighting right is important - without the main (sun) light, the scene looks drab and flat.
Apart from that the scene is quite simple - carpet, 2 flags, some lego blocks.
Here’s how the cloth works:
It’s literally just modelled down to fibre level 🙃 With path tracing this is actually viable - with many samples per pixel aliasing is not an issue, and because light bounces around within the threads the lighting and colour is realistic.
Generating this as a mesh clearly isn’t viable, so this is rendered as a raymarched SDF (signed distance field). In fact only 2 single fibres are drawn - they’re repeated, twisted around themselves to form threads, mirrored and twisted again to form ‘string’ (Lia-Sae will probably tell me that’s the wrong term ;) then repeated and woven together to form cloth.
This is how it works in cross-section:
The importance of light bounces
Each time the ray bounces, it transmits colour from the surface. This means if a ray bounces multiple times within the cloth, it both increases the brightness of the cloth and also the richness of the colour.
This turns out to be critical:
5 bounces per sample
15 bounces per sample
Of course there’s a catch: rendering geometry this fine is expensive. I optimised this to hell, and it’s still very slow - especially when many light bounces are needed. I think in the end the release version only manages ~12 samples per pixel on my GPU (a Vega 56), which is why it’s a bit noisy…