# Wavefunction Collapse

An algorithm for constraint satisfaction, commonly applied to generative image synthesis from an input image.

See description with pictures at: https://robertheaton.com/2018/12/17/wavefunction-collapse-algorithm/

# 1 Tile Extraction

Suppose tiles are D×D pixels. For simplicity assume D is odd so each tile has a unique center pixel. With 3×3 tile size, a 6×6 image will have 4×4 = 16 overlapping subtiles. Form a unique set from all the subtiles in the image (discard repeats, but count them to give a probability distribution) and label each with a distinct label (consecutive small integers are convenient).

# 2 Tile Transitions

Let N be the radius of influence. For odd D this will be N = (D + 1)/2. For each tile, and each (i,j) in (-N,-N) to (N,N) inclusive, scan the image to build an array of sets of allowed labels for each tile and offset.

# 3 Background

Initialize the output tiles to a grid with each cell containing a set of all possible labels. In C++, std::vector<bool> may be used for compact std::set<int>.

# 4 Collapse

If all cells have entropy 0, then the algorithm has finished successfully: each cell has only one tile possibility.

Otherwise, pick one of the the lowest positive entropy output cells at random, and pick one of its possibilities at random (weighted by the tile probability distribution), and collapse its possibilities to only the chosen possibility.

Then propagate constraints to neighbours (recursively).

# 5 Constraint Propagation

For a cell in the output grid, consider its neighbours with offsets (-N,-N) to (N,N) inclusive.

For each neighbour, intersect its possibilities with the union of the allowed labels for the offset (i,j) for each possibility of the original cell.

If the neighbour possibilities changed, propagate its constraints too, and so on. In this way the possibility sets are reduced in a wavefront that moves across the image.

If any possibility set becomes empty, a contradiction occured: easiest way to recover is to start over from the beginning.

# 6 Variations

If instead of extracting allowed tile transitions from the input, one extracts all possible tile transitions from the tile set by seeing how the tiles can overlap, images have a different character.

This may or may not be desirable.

# 7 Examples

# 7.1 Checkerboard

For a black and white checkerboard (1×1 cells), and 3×3 tiles, there will be two possible subtiles in the image (if it is large enough). Label them “0” for black top left pixel, “1” for white top left pixel. D = 3 so N = 2. The set of allowed neighbours of “0” will be {“0”} for offsets (i,j) where i+j is even and {“1”} for offsets (i,j) where i+j is odd. Similarly, allowed neighbours of “0” will be {“1”} for offsets (i,j) where i+j is even and {“0”} for offsets (i,j) where i+j is odd.

These sets are all singletons, so collapsing any single tile will lead to ripples collapsing all tiles in the image.

# 7.2 Checkerboards

Input input:

checkerboards with different sizes

3×3 tiles.

# 7.2.1 Transitions From Image

52 tiles, 2984 transitions.

generated checkerboards texture

# 7.2.2 Transitions from Tiles

Exhibits unexpected textures.

52 tiles, 13872 transitions.

generated checkerboards texture

# 7.3 Flowers

Input image:

pixel art flowers

Taken from https://robertheaton.com/2018/12/17/wavefunction-collapse-algorithm/ which credits https://selfsame.itch.io/unitywfc.

3×3 tiles.

# 7.3.1 Transitions From Image

Exhibits verbatim copying.

120 tiles, 6106 transitions.

generated flowers texture

# 7.3.2 Transitions from Tiles

120 tiles, 62678 transitions.

generated flowers texture

# 8 Videos

One frame is emitted each time a cell is collapsed.

# 8.1 Checkers

# 8.1.1 Transitions From Image

# 8.1.2 Transitions From Tiles

# 8.2 Flowers

# 8.2.1 Transitions From Image

# 8.2.2 Transitions From Tiles

# 9 Code

git clone https://code.mathr.co.uk/wavefunction-collapse.git

Browse: https://code.mathr.co.uk/wavefunction-collapse