Procedural Friend Generation
This is an overview of how this Godot project generates sprites. Shaders do most of the work, so that’s what I’ll explain.
Viewports/Buffers
There are 2 buffers which ping-pong off each other to allow cellular automata to be used, and a 3rd buffer which reads from the 2nd and provides color.
Shader 1: Cellular Automata
This shader runs for a fixed number of frames and uses different techniques and automata depending on the frame.
Frame 0:
The red channel draws a rectangle. The green channel draws random noise. The blue channel draws a face.
(I think medium upscaled this image to death but I’m too lazy to change it sorry)
Frames 1–9:
The green channel runs a cellular automata. Each pixel becomes the sum of it’s neighbours with the following weights:
These values were chosen by eye, not anything meaningful. This is what it looks like:
Frame 10:
Green values become thresholded.
Values below 0.1 become 1 and values above 0.1 become 0.
(The colors are being inverted, it probably isn’t necessary so sorry if that’s confusing.)
Frames 11–13:
Now the green values are either 0 or 1, we can detect corners and remove them. That is, if a green pixel == 1 and (left+right) * (top+bottom) == 1 then it becomes 0. It takes multiple frames to remove all the corners but that also means there are less connected lines, so it’s only done a few times.
Frames 14+:
Now we consider the red channel. Any green pixel with an adjacent or diagonal red neighbour becomes red, so the red rectangle from frame 0 “traverses” the greens until we stop.
Shader 2: Color
This shader runs on buffer 3 at the same time as the first shader, reads from buffer 2 (the other shader) and does the same thing every frame.
It does 4 things:
- x co-ordinates are mirrored in the centre line
- green pixels become black
- pixels with red in them become white
- blue pixels (the smile from frame 0), or black pixels with red above them become the 3rd color
That’s it!
Thanks for reading, I hope this made some sense.