what's your favorite theoretical tool for pcg?
for me it's Voronoi. it has wide applications though its simple concept.
https://redd.it/1fdzucx
@proceduralgeneration
Procedurally generating a 2d map using tilesets in UE5
Hi! I am trying to make a procedurally generated map using tilesets in C++ for my UE5 project. I want it to be like a vertical platformer rather than a top down style. I think that I am close but whenever I run this in unreal it does not draw my tiles onto the grid in the editor. I attatched the C++ code that i have to see what im missing or where im wrong. I would like to be able to input 4 different tilesets (each different biomes) and have them change depending on how vertical you manage to make it in the level. I appreciate any feedback or questions at all thanks so much!
`#include "ProceduralWorld.h"`
`#include "PaperTileMap.h"`
`#include "PaperTileSet.h"`
`#include "Engine/World.h"`
`#include "Math/UnrealMathUtility.h"`
`#include "PaperTileLayer.h"`
`// Sets default values`
`AProceduralWorld::AProceduralWorld()`
`{`
`// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.`
`PrimaryActorTick.bCanEverTick = true;`
`GridWidth = 100;`
`GridHeight = 100;`
`TileSize = 32.0f;`
`Seed = 12345; // Default seed value`
`// Create TileMapComponent`
`TileMapComponent = CreateDefaultSubobject<UPaperTileMapComponent>(TEXT("TileMapComponent"));`
`RootComponent = TileMapComponent;`
`}`
`// Called when the game starts or when spawned`
`void AProceduralWorld::BeginPlay()`
`{`
`Super::BeginPlay();`
`// Initialize the random stream with the seed`
`RandomStream.Initialize(Seed);`
`GenerateWorld();`
`}`
`// Called every frame`
`void AProceduralWorld::Tick(float DeltaTime)`
`{`
`Super::Tick(DeltaTime);`
`}`
`void AProceduralWorld::GenerateWorld()`
`{`
`// Create a new TileMap`
`UPaperTileMap* TileMap = NewObject<UPaperTileMap>(this);`
`TileMap->MapWidth = GridWidth;`
`TileMap->MapHeight = GridHeight;`
`TileMap->TileWidth = TileSize;`
`TileMap->TileHeight = TileSize;`
`TileMap->PixelsPerUnrealUnit = 1.0f;`
`TileMap->SeparationPerTileX = 0.0f;`
`TileMap->SeparationPerTileY = 0.0f;`
`TileMap->SeparationPerLayer = 0.0f;`
`TileMapComponent->SetTileMap(TileMap);`
`//GenerateTerrainFormations();`
`for (int32 X = 0; X < GridWidth; ++X)`
`{`
`for (int32 Y = 0; Y < GridHeight; ++Y)`
`{`
`// Determine the biome type for the current tile`
`EBiomeType BiomeType = DetermineBiome(X, Y);`
`// Select the appropriate tile set based on the biome type`
`UPaperTileSet* TileSet = nullptr;`
`switch (BiomeType)`
`{`
`case EBiomeType::Underground:`
`TileSet = UndergroundTileSet;`
`break;`
`case EBiomeType::Forest:`
`TileSet = ForestTileSet;`
`break;`
`case EBiomeType::Crystal:`
`TileSet = CrystalTileSet;`
`break;`
`case EBiomeType::Mountain:`
`TileSet = MountainTileSet;`
`break;`
`}`
`// Set the tile in the TileMap`
`if (TileSet)`
`{`
`int32 TileIndex = GetWangTileIndex(X, Y, TileSet);`
`SetTile(X, Y, TileSet, 4);`
`}`
`}`
`}`
`}`
`EBiomeType AProceduralWorld::DetermineBiome(int32 X, int32 Y)`
`{`
`if (Y < 2000)`
`{`
`return EBiomeType::Underground;`
`}`
`else if (Y > 2000 && Y < 5000 && X < 4000)`
`{`
`return EBiomeType::Forest;`
`}`
`else if (Y > 5000 && Y < 7500 && X > 4000)`
`{`
`return EBiomeType::Crystal;`
`}`
`else`
`{`
`return EBiomeType::Mountain;`
`}`
`}`
`void AProceduralWorld::SetTile(int32 X, int32 Y, UPaperTileSet* TileSet, int32 TileIndex)`
`{`
`if (TileMapComponent && TileSet)`
`{`
`FPaperTileInfo TileInfo;`
`TileInfo.TileSet = TileSet;`
`TileInfo.PackedTileIndex = TileIndex;`
`TileMapComponent->SetTile(X, Y, 0, TileInfo);`
`}`
`}`
`int32 AProceduralWorld::GetWangTileIndex(int32 X, int32 Y, UPaperTileSet* TileSet)`
`{`
`// Example logic to determine Wang tile index based on neighbors`
`// This is a simplified version; you can expand it based on your needs`
`int32 NeighborMask = 0;`
`// Check 4 neighbors (N, E, S, W) and create a bitmask`
`if (X > 0 && TileMapComponent->GetTile(X - 1, Y, 0).TileSet == TileSet) NeighborMask |= 1; // West`
`if (Y > 0 && TileMapComponent->GetTile(X, Y - 1, 0).TileSet == TileSet) NeighborMask |=
Perlin noise with default lower frequency?
Hi. I'm making a procedural generated landscape and have ran into a problem. I'm feeding the noise function I'm using with world coordinates where 1 unit is one meter. This results in a very high frequency noise by default so I have to scale down the input coordinates a lot to get low frequency which can create accurate sized hills and mountains. This works well for the terrain geometry which have a minimal vertex spacing of 0.5 meters.
But I'm also generating textures and in the highest resolution (when closest to ground) I am dealing with sampling steps which are 0.03125 per sample point. Since I have to downscale the world coordinates by a factor of 10000 to get the frequency I require this results in floating point precision issues at those small increments. So one or more adjacent sample points can become the exact same position which in turn results in the exact same noise value. This is a problem becuase I need to efficiently calculate normals per texel for texture blending. And if I can't calculate a normal from the adjacent height values (because they are the same) it completely ruins everything.
I could of course take samples with a set minimum offset which would guarantee that all samples are different, but for performance requirments this is out of the question, I need to make use of the samples already calculated by adjacent threads in the compute shader to get anywhere near acceptable performance.
So I started to think that there must be some way to have the noise function be much lower frequency by default so I don't need to downscale the input coordinates at all and get into this precision issue. I can't use doubles either as that is massively murdering the performance on a GPU.
Unfortunately I don't really "get" how perlin noise works and my attempts to modify the function I'm using have failed spectacularly. So I was wondering if anyone knows this and how it's typically solved.
The perlin function I'm using is this one: https://github.com/BrianSharpe/Wombat/blob/master/Perlin2D\_Deriv.glsl
Example of the problem I'm facing
Blending issue close up due to incorrect normals
Properly looking textures from a far
https://redd.it/1fdbu86
@proceduralgeneration
How to weight procedural generation based on previous picks
The title is not worded well, sorry, but I couldn't think at anything different.
The jist of the thing is this: I want to write an NPC procedural generation routine that chooses a random number of personality traits, and in which each subsequent trait is informed by the previous ones to some degree (so that, for example, if it picks "lazy" as first choice, it doesn't picks "sporty" as the second one because it doesn't make too much sense).
I'm still learning, so this might be a very easy problem to solve, but as of now I have no idea how to tackle it without creating an angodly amount of lookup tables for each combination.
Can you help me with ideas and learning material? Thanks!
https://redd.it/1fbxuzw
@proceduralgeneration
Terrain generation using OpenSimplex and simple tectonic plate simulation(via a Voronoi diagram).
https://preview.redd.it/ds22tpu4qand1.png?width=1504&format=png&auto=webp&s=fb8147a2bf8fe9b79557ee2607a17031ac1ddb83
Seed I used while testing. Rivers where generated using by picking random points above an elevation then following the slope of the elevation down, creating lakes whenever they flowed into valleys.
https://preview.redd.it/ry9sjez7qand1.png?width=1504&format=png&auto=webp&s=5c685ca6a709981da34d3c305abd9caa1ad5dc32
Tectonic plates layered on top of the terrain. They where generated using a Voronoi diagram then each plate was given a random velocity(green asterisks). Plate collisions where then determined using the plates vectors and positions. Boundary types are as follows: red, convergent; orange, divergent; and pink, transform. Convergent boundaries create mountain ranges/island chains and divergent boundaries create create rift valleys. The height of mountain ranges somewhat vary based on the intensity of the plate collisions. Please note: I am not a geologist so my understanding of how plate boundaries effect terrain is most likely incorrect.
https://preview.redd.it/76vf2x13rand1.png?width=1504&format=png&auto=webp&s=584bfd68ce529cfd90a2f39eeefc238ab7732ce8
Pure elevation map created with multiple arrays of OpenSimplex noise at different octaves added together in addition to the modifications made by the plate boundaries.
https://redd.it/1fawnqw
@proceduralgeneration
Chat controls AI visuals, I play music
https://www.youtube.com/watch?v=ax6kTe7SPVo
https://redd.it/1f90bn4
@proceduralgeneration
NFTs - someone point me in the right direction
This may not be the right forum to ask this. If not, just let me know. Keep in mind you are dealing with a complete noob here. I know nothing about procedural generation. Here's what I want to do. I want to create a NFT collection of wolves to support my fiction universe. Since, I have no artistic ability, I wanted to start with an AI generated image, then use procedural generation to change the attributes (diff hair, sunglasses etc.). I have no clue how to get started. Can anyone help me with this? Thanks in advance.
https://redd.it/1f6oidv
@proceduralgeneration
I'm skeptical that this is proper implementation of Wilson's algorithm
https://i.redd.it/depgpr9tv5md1.gif
It takes quite a while for the random walk to reach the first white cell, but if you are patient and watch it through to the end, the gif will eventually terminate with a completed maze.
It looks like always converging and terminating in finite time, but when i increase the maze size, the consuming time drastically increases due to its stochastic nature. how to fix it? at the first place, did i properly implement the algorithm?
I know there are many other algorithms for generating mazes other than Wilson's. But this question focuses on Wilson only.
I share my Python source code below. it's a bit dirty and not well-organized, so feel free to ask me if you are wondering the code.
def random_step(r, c, R, C):
dir = [(0, 1), (1, 0), (0, -1), (-1, 0)]
neighbors = []
for dr, dc in dir:
nr, nc = r + dr, c + dc
if 0 <= nr < R and 0 <= nc < C:
neighbors.append((nr, nc))
return random.choice(neighbors)
from PIL import Image, ImageDraw
def draw_maze(maze, path, nonust, uniform_scale):
R, C = len(maze), len(maze[0])
img_size = (C * uniform_scale, R * uniform_scale)
img = Image.new("RGB", img_size, "black")
drawer = ImageDraw.Draw(img)
for r in range(R):
for c in range(C):
x0, y0 = c * uniform_scale, r * uniform_scale
x1, y1 = x0 + uniform_scale, y0 + uniform_scale
if (r, c) not in nonust:
drawer.rectangle([x0, y0, x1, y1], fill="white")
elif (r, c) in path:
drawer.rectangle([x0, y0, x1, y1], fill="gray")
# elif maze[r][c] == (True, True, True, True):
# drawer.rectangle([x0, y0, x1, y1], fill="white")
else:
drawer.rectangle([x0, y0, x1, y1], fill="pink")
if maze[r][c][0]:
drawer.line([x0, y0, x1, y0], fill="brown", width=2)
if maze[r][c][1]:
drawer.line([x1, y0, x1, y1], fill="brown", width=2)
if maze[r][c][2]:
drawer.line([x0, y1, x1, y1], fill="brown", width=2)
if maze[r][c][3]:
drawer.line([x0, y0, x0, y1], fill="brown", width=2)
return img
def Wilson(R, C, uniform_scale):
maze = [[[True, True, True, True] for _ in range(C)] for _ in range(R)]
frames = []
nonust = {(i, j) for j in range(C) for i in range(R)}
r0, c0 = random.randint(0, R - 1), random.randint(0, C - 1)
nonust.discard((r0, c0))
maze[r0][c0] = [True, True, True, True]
while len(nonust) > 0:
startr, startc = random.choice(list(nonust))
path = [(startr, startc)]
while path[-1] in nonust:
r, c = path[-1]
nr, nc = random_step(r, c, R, C)
if (nr, nc) in path:
path = path[: path.index((nr, nc)) + 1]
else:
path.append((nr, nc))
frames.append(draw_maze(maze, path, nonust, uniform_scale))
for i in range(len(path) - 1):
r, c = path[i]
nr, nc = path[i + 1]
if nr == r - 1:
maze[r][c][0] = False
maze[nr][nc][2] = False
elif nr == r + 1:
maze[r][c][2] = False
maze[nr][nc][0] = False
elif nc == c - 1:
maze[r][c][3] = False
maze[nr][nc][1] = False
elif nc == c + 1:
maze[r][c][1] = False
maze[nr][nc][3] = False
nonust.discard((r, c))
frames.append(draw_maze(maze, path, nonust, uniform_scale))
frames[0].save(
"Wilson.gif",
save_all=True,
Help with identifying and filling gaps in procedural junction geometry
https://www.reddit.com/gallery/1f67xuk
https://redd.it/1f6807l
@proceduralgeneration
Some progress updates and previews of regional map generation on my fully procgen'd RPG in the making.
https://www.youtube.com/watch?v=Qc_nNZCSoBk
https://redd.it/1f5w6f2
@proceduralgeneration
2; // South`
`if (X < GridWidth - 1 && TileMapComponent->GetTile(X + 1, Y, 0).TileSet == TileSet) NeighborMask |= 4; // East`
`if (Y < GridHeight - 1 && TileMapComponent->GetTile(X, Y + 1, 0).TileSet == TileSet) NeighborMask |= 8; // North`
`// Use the bitmask to determine the tile index`
`// This is a placeholder; you can map the bitmask to specific tile indices`
`return NeighborMask % TileSet->GetTileCount();`
`}`
`void AProceduralWorld::GenerateTerrainFormations()`
`{`
`// Generate base terrain using Perlin noise`
`for (int32 X = 0; X < GridWidth; ++X)`
`{`
`for (int32 Y = 0; Y < GridHeight; ++Y)`
`{`
`float NoiseValue = PerlinNoise(X * 0.1f, Y * 0.1f);`
`if (NoiseValue < 0.4f)`
`{`
`// Set as wall`
`SetTile(X, Y, UndergroundTileSet, 1); // Assuming 1 is the wall tile index`
`}`
`else`
`{`
`// Set as floor`
`SetTile(X, Y, UndergroundTileSet, 0); // Assuming 0 is the floor tile index`
`}`
`}`
`}`
`// Refine terrain using cellular automata`
`ApplyCellularAutomata();`
`}`
`float AProceduralWorld::PerlinNoise(float X, float Y)`
`{`
`// Simple Perlin noise implementation using Unreal's noise functions`
`return FMath::PerlinNoise2D(FVector2D(X, Y));`
`}`
`void AProceduralWorld::ApplyCellularAutomata()`
`{`
`TArray<TArray<int32>> Grid;`
`Grid.SetNum(GridWidth);`
`for (int32 X = 0; X < GridWidth; ++X)`
`{`
`Grid[X].SetNum(GridHeight);`
`}`
`// Initialize the grid with Perlin noise`
`for (int32 X = 0; X < GridWidth; ++X)`
`{`
`for (int32 Y = 0; Y < GridHeight; ++Y)`
`{`
`float NoiseValue = PerlinNoise(X * 0.1f, Y * 0.1f);`
`Grid[X][Y] = (NoiseValue < 0.4f) ? 1 : 0; // 1 for wall, 0 for floor`
`}`
`}`
`// Apply cellular automata rules`
`for (int32 Iteration = 0; Iteration < 5; ++Iteration)`
`{`
`TArray<TArray<int32>> NewGrid = Grid;`
`for (int32 X = 1; X < GridWidth - 1; ++X)`
`{`
`for (int32 Y = 1; Y < GridHeight - 1; ++Y)`
`{`
`int32 WallCount = 0;`
`// Count the number of walls in the 8 neighboring cells`
`for (int32 OffsetX = -1; OffsetX <= 1; ++OffsetX)`
`{`
`for (int32 OffsetY = -1; OffsetY <= 1; ++OffsetY)`
`{`
`if (OffsetX != 0 || OffsetY != 0)`
`{`
`WallCount += Grid[X + OffsetX][Y + OffsetY];`
`}`
`}`
`}`
`// Apply the rules of cellular automata`
`if (WallCount > 4)`
`{`
`NewGrid[X][Y] = 1; // Become a wall`
`}`
`else if (WallCount < 4)`
`{`
`NewGrid[X][Y] = 0; // Become a floor`
`}`
`}`
`}`
`Grid = NewGrid;`
`}`
`// Set the tiles based on the final grid`
`for (int32 X = 0; X < GridWidth; ++X)`
`{`
`for (int32 Y = 0; Y < GridHeight; ++Y)`
`{`
`if (Grid[X][Y] == 1)`
`{`
`SetTile(X, Y, UndergroundTileSet, 1); // Assuming 1 is the wall tile index`
`}`
`else`
`{`
`SetTile(X, Y, UndergroundTileSet, 0); // Assuming 0 is the floor tile index`
`}`
`}`
`}`
`}`
https://redd.it/1fdvp5t
@proceduralgeneration
I spent the last three and a half years learning to build a voxel terrain generator in Unreal. This is the result.
After years of hard work, I'm excited to share the Infinite Voxel Terrain Plugin, a voxel terrain generator designed specifically for Unreal Engine. It’s a multithreaded, region-based system built with multiplayer in mind, ensuring smooth replication of voxel changes and efficient network performance. Here are some of the main features:
https://preview.redd.it/126bcmzeu1od1.png?width=1920&format=png&auto=webp&s=9b3358a77762b6a9e032db30f10ab124ff2cb7ed
* Multithreading & Performance: Generates terrain chunks in parallel, providing fast world creation without compromising performance.
* Region-Based Data Management: Loads and saves only the necessary regions, keeping memory usage and network load optimized.
* Virtually Unlimited Build Heights: The vertical chunk system adapts dynamically, so you can build from the deepest caverns to the highest mountains.
* FastNoise2 Integration: Create varied landscapes using versatile noise functions, with the ability to use the FastNoise tool from Auburn to create new terrain types.
* Easy Voxel Customization: Adding new voxel types is as simple as updating the material and texture, making the plugin highly flexible.
The plugin is available now for $119.99 as I continue refining it with updates—expect the price to rise as features expand. If you have any questions or want to see more, feel free to ask!
[https://www.unrealengine.com/marketplace/en-US/product/4dee9a793a2b412fa3b193cfae8d24e6](https://www.unrealengine.com/marketplace/en-US/product/4dee9a793a2b412fa3b193cfae8d24e6)
Thank you for checking out my work, and I hope it can help bring your voxel-based worlds to life.
https://redd.it/1fdtbp4
@proceduralgeneration
Mario world map generated from global terrain data
https://redd.it/1fco92q
@proceduralgeneration
Want to simulate a couple of scenes where a person is in danger or threat by another individual, how do I proceed with this in Unreal and possibly using Procedural Generation
So I have been working on a project where I need to detect a person is in danger by any physical means threatened by another individual or group of Individuals, I have some basic idea of Unreal for Game development but this simulation and procedural generation is totally new for me so any advice regarding the same will be appreciated
https://redd.it/1fbd2cp
@proceduralgeneration
Procedural Planet Rendering
Space view
Another space view
Closer
Even closer
https://preview.redd.it/2kz8dq3bd5nd1.png?width=1919&format=png&auto=webp&s=da05d7ec1c2610213dc6bd605c8e691ebc0fcabf
Recently I have been working on a little opengl renderer for procedural planets, with the eventual goal of expanding to an entire universe. These are some screenshots I really enjoyed and wanted to show off. I have some videos of flight on my youtube channel: https://youtu.be/SaLLzhwu-J8?feature=shared
https://redd.it/1faa1ko
@proceduralgeneration
Procedural planet generation based on plate tectonics, basic fluid and climate simulations for my game
https://redd.it/1f9iipp
@proceduralgeneration
QUESTION: need help identifying the kind of maths used to generate the forms seen in the YouTube video
https://www.youtube.com/watch?v=OmRL9ZBgwPQ&list=PLQBIOV-hHB3wUm\_c-v2wa1pPpk-l6vBrZ&index=21
new programmer. Not very mathy
i'm sure what i'm looking for is related to fourier, lissajous, wave functions, periodic functions, dynamic functions, parametric, generate, kinetic, epicycles, chaos theory, uniformly rotating circles/compasses, maybe euler and maxwell equations....... but this is just alot of words to me in a google hole........... when i'm sure what im looking for is a simple field of maths or family of equations or algorithms or something.
really just looking for simple ways to implement the kind of forms seen in the video in a plotter like matplotlib (i'll look into p5 later) that I can add live updating of parameters to and other simple-ish things like algorithms for floatiness, parallax motion, and simple noise.
not looking for complex shaders or advanced stuff. just nice, varied geometry plots that, with parameters, can be animated to move between very ordered and mandala-esque, to random chaotic squigglies.
pointers in the right direction greatly appreciated!
https://redd.it/1f8xv7c
@proceduralgeneration
Since it looks like you are not already bored by my last bags of random pixels, here is more! Yay!
https://redd.it/1f79hni
@proceduralgeneration
append_images=frames[1:],
duration=0.5,
loop=0,
)
https://redd.it/1f6a1j8
@proceduralgeneration
I'm skeptical that this is proper implementation of Wilson's algorithm
https://i.redd.it/depgpr9tv5md1.gif
It takes quite a while for the random walk to reach the first white cell, but if you are patient and watch it through to the end, the gif will eventually terminate with a completed maze.
It looks like always converging and terminating in finite time, but when i increase the maze size, the consuming time drastically increases due to its stochastic nature. how to fix it? at the first place, did i properly implement the algorithm?
I know there are many other algorithms for generating mazes other than Wilson's. But this question focuses on Wilson only.
I share my Python source code below. it's a bit dirty and not well-organized, so feel free to ask me if you are wondering the code.
def randomstep(r, c, R, C):
dir = [(0, 1), (1, 0), (0, -1), (-1, 0)]
neighbors = []
for dr, dc in dir:
nr, nc = r + dr, c + dc
if 0 <= nr < R and 0 <= nc < C:
neighbors.append((nr, nc))
return random.choice(neighbors)
from PIL import Image, ImageDraw
def drawmaze(maze, path, nonust, uniformscale):
R, C = len(maze), len(maze[0])
imgsize = (C uniform_scale, R uniformscale)
img = Image.new("RGB", imgsize, "black")
drawer = ImageDraw.Draw(img)
for r in range(R):
for c in range(C):
x0, y0 = c uniform_scale, r uniformscale
x1, y1 = x0 + uniformscale, y0 + uniformscale
if (r, c) not in nonust:
drawer.rectangle([x0, y0, x1, y1], fill="white")
elif (r, c) in path:
drawer.rectangle([x0, y0, x1, y1], fill="gray")
# elif maze[r][c] == (True, True, True, True):
# drawer.rectangle([x0, y0, x1, y1], fill="white")
else:
drawer.rectangle([x0, y0, x1, y1], fill="pink")
if maze[r][c][0]:
drawer.line([x0, y0, x1, y0], fill="brown", width=2)
if maze[r][c][1]:
drawer.line([x1, y0, x1, y1], fill="brown", width=2)
if maze[r][c][2]:
drawer.line([x0, y1, x1, y1], fill="brown", width=2)
if maze[r][c][3]:
drawer.line([x0, y0, x0, y1], fill="brown", width=2)
return img
def Wilson(R, C, uniformscale):
maze = [[True, True, True, True for in range(C)] for in range(R)]
frames =
nonust = {(i, j) for j in range(C) for i in range(R)}
r0, c0 = random.randint(0, R - 1), random.randint(0, C - 1)
nonust.discard((r0, c0))
mazer0c0 = True, True, True, True
while len(nonust) > 0:
startr, startc = random.choice(list(nonust))
path = (startr, startc)
while path-1 in nonust:
r, c = path-1
nr, nc = randomstep(r, c, R, C)
if (nr, nc) in path:
path = path[: path.index((nr, nc)) + 1]
else:
path.append((nr, nc))
frames.append(drawmaze(maze, path, nonust, uniformscale))
for i in range(len(path) - 1):
r, c = path[i]
nr, nc = path[i + 1]
if nr == r - 1:
maze[r][c][0] = False
maze[nr][nc][2] = False
elif nr == r + 1:
maze[r][c][2] = False
maze[nr][nc][0] = False
elif nc == c - 1:
maze[r][c][3] = False
maze[nr][nc][1] = False
elif nc == c + 1:
maze[r][c][1] = False
maze[nr][nc][3] = False
nonust.discard((r, c))
frames.append(drawmaze(maze, path, nonust, uniformscale))
frames[0].save(
"Wilson.gif",
saveall=True,
My talk about extending Wave Function Collapse is now online. I presented this at Everything Procedural 2024.
https://www.youtube.com/watch?v=1tgMl92DAqk
https://redd.it/1f5rgp3
@proceduralgeneration