procedural generation
108 subscribers
4.58K photos
1.36K videos
2 files
10K links
Created by @r_channels
Download Telegram
I used WFC but result is not good.

https://preview.redd.it/bs08bd71m9bf1.png?width=1040&format=png&auto=webp&s=7ce2a45abd9f4ede87935527f74a84922f93ca8f

In the end it turned out to be some kind of mishmash of objects. Can you help me find out what's wrong?

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO.Compression;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.Tilemaps;

public class WaveFunction : MonoBehaviour
{
    public int dimensions;
    public Tie tileObjects;
    public List<Cell> gridCompoments;
    public Cell cellObj;

    public float tileSize = 1.0f;

    int iterations = 0;

    void Awake()
    {
        gridCompoments = new List<Cell>();
        InitializeGrid();
    }

    void InitializeGrid()
    {
        for (int z = 0; z < dimensions; z++)
        {
            for (int x = 0; x < dimensions; x++)
            {
                Vector3 pos = new Vector3(x tileSize, 0, z tileSize); // Y = 0
                Cell newCell = Instantiate(cellObj, pos, Quaternion.identity);
                newCell.CreateCell(false, tileObjects);
                gridCompoments.Add(newCell);
            }
        }

        StartCoroutine(CheckEntropy());
    }

    IEnumerator CheckEntropy()
    {
        List<Cell> tempGrid = new List<Cell>(gridCompoments);

        tempGrid.RemoveAll(c => c.collapsed);

        tempGrid.Sort((a, b) => { return a.tileOptions.Length - b.tileOptions.Length; });

        int arrLenght = tempGrid0.tileOptions.Length;
        int stopIndex = default;

        for (int i = 1; i < tempGrid.Count; i++)
        {
            if (tempGridi.tileOptions.Length > arrLenght)
            {
                stopIndex = i;
                break;
            }
        }

        if (stopIndex > 0)
        {
            tempGrid.RemoveRange(stopIndex, tempGrid.Count - stopIndex);
        }

        yield return new WaitForSeconds(0.01f);

        CollapseCell(tempGrid);
    }

    void CollapseCell(List<Cell> tempGrid)
    {
        int randIndex = UnityEngine.Random.Range(0, tempGrid.Count);

        Cell cellToCollapse = tempGridrandIndex;

        cellToCollapse.collapsed = true;
        Tie selectedTile = cellToCollapse.tileOptionsUnityEngine.Random.Range(0, cellToCollapse.tileOptions.Length);
        cellToCollapse.tileOptions = new Tie { selectedTile };

        Tie foundTile = cellToCollapse.tileOptions0;
        Instantiate(foundTile, cellToCollapse.transform.position, Quaternion.identity);

        UpdateGeneration();
    }

    void UpdateGeneration()
    {
        List<Cell> newGenerationCell = new List<Cell>(gridCompoments);

        for (int z = 0; z < dimensions; z++)
        {
            for (int x = 0; x < dimensions; x++)
            {
                int index = GetIndex(x, z);
                Cell currentCell = gridCompomentsindex;

                if (currentCell.collapsed)
                {
                    newGenerationCellindex = currentCell;
                }
                else
                {
                    List<Tie> options = new List<Tie>(tileObjects);

                    // LEFT
                    if (x > 0)
                        ApplyConstraint(x - 1, z, "XP", options);

                    // RIGHT
                    if (x < dimensions - 1)
                        ApplyConstraint(x + 1, z, "XM", options);

                    // FORWARD
                    if (z < dimensions - 1)
                        ApplyConstraint(x, z + 1, "ZM",
I used WFC but result is not good.

https://preview.redd.it/bs08bd71m9bf1.png?width=1040&format=png&auto=webp&s=7ce2a45abd9f4ede87935527f74a84922f93ca8f

In the end it turned out to be some kind of mishmash of objects. Can you help me find out what's wrong?

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO.Compression;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.Tilemaps;

public class WaveFunction : MonoBehaviour
{
    public int dimensions;
    public Tie[] tileObjects;
    public List<Cell> gridCompoments;
    public Cell cellObj;

    public float tileSize = 1.0f;

    int iterations = 0;

    void Awake()
    {
        gridCompoments = new List<Cell>();
        InitializeGrid();
    }

    void InitializeGrid()
    {
        for (int z = 0; z < dimensions; z++)
        {
            for (int x = 0; x < dimensions; x++)
            {
                Vector3 pos = new Vector3(x * tileSize, 0, z * tileSize); // Y = 0
                Cell newCell = Instantiate(cellObj, pos, Quaternion.identity);
                newCell.CreateCell(false, tileObjects);
                gridCompoments.Add(newCell);
            }
        }

        StartCoroutine(CheckEntropy());
    }

    IEnumerator CheckEntropy()
    {
        List<Cell> tempGrid = new List<Cell>(gridCompoments);

        tempGrid.RemoveAll(c => c.collapsed);

        tempGrid.Sort((a, b) => { return a.tileOptions.Length - b.tileOptions.Length; });

        int arrLenght = tempGrid[0].tileOptions.Length;
        int stopIndex = default;

        for (int i = 1; i < tempGrid.Count; i++)
        {
            if (tempGrid[i].tileOptions.Length > arrLenght)
            {
                stopIndex = i;
                break;
            }
        }

        if (stopIndex > 0)
        {
            tempGrid.RemoveRange(stopIndex, tempGrid.Count - stopIndex);
        }

        yield return new WaitForSeconds(0.01f);

        CollapseCell(tempGrid);
    }

    void CollapseCell(List<Cell> tempGrid)
    {
        int randIndex = UnityEngine.Random.Range(0, tempGrid.Count);

        Cell cellToCollapse = tempGrid[randIndex];

        cellToCollapse.collapsed = true;
        Tie selectedTile = cellToCollapse.tileOptions[UnityEngine.Random.Range(0, cellToCollapse.tileOptions.Length)];
        cellToCollapse.tileOptions = new Tie[] { selectedTile };

        Tie foundTile = cellToCollapse.tileOptions[0];
        Instantiate(foundTile, cellToCollapse.transform.position, Quaternion.identity);

        UpdateGeneration();
    }

    void UpdateGeneration()
    {
        List<Cell> newGenerationCell = new List<Cell>(gridCompoments);

        for (int z = 0; z < dimensions; z++)
        {
            for (int x = 0; x < dimensions; x++)
            {
                int index = GetIndex(x, z);
                Cell currentCell = gridCompoments[index];

                if (currentCell.collapsed)
                {
                    newGenerationCell[index] = currentCell;
                }
                else
                {
                    List<Tie> options = new List<Tie>(tileObjects);

                    // LEFT
                    if (x > 0)
                        ApplyConstraint(x - 1, z, "XP", options);

                    // RIGHT
                    if (x < dimensions - 1)
                        ApplyConstraint(x + 1, z, "XM", options);

                    // FORWARD
                    if (z < dimensions - 1)
                        ApplyConstraint(x, z + 1, "ZM",
options);

                    // BACKWARD
                    if (z > 0)
                        ApplyConstraint(x, z - 1, "ZP", options);

                    Tie[] newTileList = options.ToArray();
                    newGenerationCell[index].RecreateCell(newTileList);
                }
            }
        }

        gridCompoments = newGenerationCell;
        iterations++;

        if (iterations < dimensions * dimensions)
        {
            StartCoroutine(CheckEntropy());
        }
    }

    int GetIndex(int x, int z)
    {
        return x + z * dimensions;
    }

    void ApplyConstraint(int x, int z, string direction, List<Tie> options)
    {
        Cell neighbor = gridCompoments[GetIndex(x, z)];
        List<Tie> validOptions = new List<Tie>();

        foreach (Tie possible in neighbor.tileOptions)
        {
            int idx = Array.FindIndex(tileObjects, obj => obj == possible);

            Tie[] valid = possible.GetNeighbors(direction, neighbor.rotation);

            validOptions = validOptions.Concat(valid).ToList();
        }

        CheckValidity(options, validOptions);
    }

    void CheckValidity(List<Tie> optionsList, List<Tie> validOption)
    {
        for (int x = optionsList.Count - 1; x >= 0; x--)
        {
            var element = optionsList[x];
            if (!validOption.Contains(element))
            {
                optionsList.RemoveAt(x);
            }
        }
    }
}

using UnityEngine;
using UnityEngine.Tilemaps;

public class Cell : MonoBehaviour
{
    public bool collapsed;
    public Tie[] tileOptions;
    public int rotation;

    public void CreateCell(bool collapseState, Tie[] tiles)
    {
        collapsed = collapseState;
        tileOptions = tiles;
    }

    public void RecreateCell(Tie[] tiles)
    {
        tileOptions = tiles;
    }
}


using System;
using UnityEngine;

public enum Direction { North_ZP, South_ZM, East_XP, West_XM }
public class Tie : MonoBehaviour
{
    [Header("BVars:")]
    public string type;
    public Direction[] connections;
    [Header("Other Vars:")]
    public Tie[] ZP_neighbors; //Up
    public Tie[] ZM_neighbors; //Down

    public Tie[] XP_neighbors; //Right
    public Tie[] XM_neighbors; //Left

    public Tie[] GetNeighbors(string direction, int rotation)
    {

        int dirIndex = direction switch
        {
            "XP" => 0,
            "ZP" => 1,
            "XM" => 2,
            "ZM" => 3,
            _ => -1
        };

        int rotatedDirIndex = (dirIndex - rotation + 4) % 4;

        switch(rotatedDirIndex)
        {
            case 0: return XP_neighbors;
            case 1: return ZP_neighbors;
            case 2: return XM_neighbors;
            case 3: return ZM_neighbors;
            default: return Array.Empty<Tie>();
        }
    }
}




https://redd.it/1lt2rfj
@proceduralgeneration
Media is too big
VIEW IN TELEGRAM
I've been cooking also pretty sure this is the first universe sim of its kind ever to fully simulate universal age based on the most popular and real theory of heat death it still needs some baking and i need to add black dwarfs

https://redd.it/1luvg46
@proceduralgeneration
I'm now creating webapp to share seeds (balatro and other procedure generation based games), and I can't stop thinking about this domain. I mean, it's 30$, but I really can't stop thinking about it
https://redd.it/1lv1tdo
@proceduralgeneration
Convert pixel-art-style images from GPT-4o into true pixel resolution assets

GPT-4o has a fantastic image generator and can turn images into a pixel-art-like style. However, the raw output is generally unusable as an asset due to

High noise
High resolution
Inconsistent grid spacing
Random artifacts

Due to these issues, regular down-sampling techniques do not work, and the only options are to either use a down-sampling method that does not produce a result that is faithful to the original image, or manually recreate the art pixel by pixel.

Additionally, these issues make raw outputs very difficult to edit and fine-tune. I created an algorithm that post-processes pixel-art-style images generated by GPT-4o, and outputs the true resolution image as a usable asset. It also works on images of pixel art from screenshots and fixes art corrupted by compression.

The tool is available to use with an explanation of the algorithm on my GitHub here!

P.S. if you are trying to use this and not getting the results you would like feel free to reach out!

https://redd.it/1lvk9wp
@proceduralgeneration
Nova Patria - A Roman Steampunk Colony Sim - now has a Steam page!
https://redd.it/1lvmd4f
@proceduralgeneration
Media is too big
VIEW IN TELEGRAM
Working on a Procedural Village Generator – I Would Love Some Feed Back. What Visuals or Features Would Make It Really Pop?

https://redd.it/1lvt9ex
@proceduralgeneration
Looking for advice on how to classify terrain based on a height map

To be brief I am trying to make an island generator that sets tiles based on height; however, I was wondering if there was a more efficient way to loop through different tiles and assign based on height rather than just a bunch of if statements. Additionally I am using a random function bounded by ranges that i feel are reasonable(they might not be I'm new to this) to give a more varied result. here is the code in GD script (\~ python) if my explanation was unsatisfactory

extends TileMapLayer



#constants

var map_size := 300

var gradient:=.45 # must be 0<x<.5 effects how far out the island can go with a max value of .5



# __innit__

var fnl := FastNoiseLite.new()

var random := RandomNumberGenerator.new()



#Fast_Noise_Light -----------------------------------------------------

# General

var frequency := Vector2(0.01, 0.1) # Scale, larger = smoother, smaller = more detial



# Fractal

var f_octaves := Vector2(3, 8) # layers of noise

var f_lacuranity := Vector2(1.5, 3.0) # essentially applies zoom to an octave

var F_gain := Vector2(0.3, 0.7) # Strength of each subsequent octave

var f_weighted_strength := Vector2(0.0, 1.0) #str of subsequent octaves blending

var f_ping_pong_strength := Vector2(0.0, .5) # cuases more repetitive terrain, well keep this low



# Domain Warp

var dm_amplitude := Vector2(5.0, 30.0) # Warp strength

var dm_frequency := Vector2(0.01, 0.1) # Frequency for warp, same general concept



# Domain Warp Fractal

var dwf_octaves := Vector2(2, 5) #^ but for warp

var dwf_lacuranity := Vector2(2.0, 6.0) #^ but for warp

var dwf_gain := Vector2(0.3, 0.7) #^ but for warp











# Called when the node enters the scene tree for the first time.

func _ready() -> void:

fnl.seed = randi()

fnl.noise_type = FastNoiseLite.TYPE_SIMPLEX_SMOOTH

fnl.frequency = random.randf_range(frequency.x, frequency.y)

fnl.fractal_octaves = random.randi_range(f_octaves.x, f_octaves.y)

fnl.fractal_lacunarity = random.randf_range(f_lacuranity.x, f_lacuranity.y)

fnl.fractal_gain = random.randf_range(F_gain.x, F_gain.y)

fnl.fractal_weighted_strength = random.randf_range(f_weighted_strength.x, f_weighted_strength.y)

fnl.fractal_ping_pong_strength = random.randf_range(f_ping_pong_strength.x, f_ping_pong_strength.y)

fnl.domain_warp_amplitude = random.randf_range(dm_amplitude.x, dm_amplitude.y)

fnl.domain_warp_frequency = random.randf_range(dm_frequency.x, dm_frequency.y)

fnl.domain_warp_fractal_octaves = random.randi_range(dwf_octaves.x, dwf_octaves.y)

fnl.domain_warp_fractal_lacunarity = random.randf_range(dwf_lacuranity.x, dwf_lacuranity.y)

fnl.domain_warp_fractal_gain = random.randf_range(dwf_gain.x, dwf_gain.y)

generate_map()





# Called every frame. 'delta' is the elapsed time since the previous frame.

func _process(delta: float) -> void:

generate_map()



func border(noise_topo,x:int,y:int):

var center = Vector2(map_size/2,map_size/2)

var new_noise = fnl.get_noise_2d(x*.01,y*.01)

var current_pos = Vector2(x, y)

var euclid = (current_pos - center).length()

var max = euclid*gradient

var adjusted_val = max*noise_topo*30

noise_topo = adjusted_val+noise_topo

return noise_topo



pass

func generate_map():





for x in map_size:

for y in map_size:

var noise_topo:= fnl.get_noise_2d(x,y)

var noise_topo_2 = border(noise_topo,x,y)

if noise_topo_2 < -0.2:

set_cell(Vector2i(x, y), 0, Vector2i(2, 4)) # Water

elif noise_topo_2 < 0.4:

set_cell(Vector2i(x, y), 0, Vector2i(0, 4)) # Grass

else:

set_cell(Vector2i(x, y), 0, Vector2i(4, 4)) # Stone



https://redd.it/1lvwpks
@proceduralgeneration
House/Room Layout Generation Paper

I've become borderline obsessed with house exterior and interior runtime generation, but I've struggled to find resources that don't rely on AI to make it happen.

I also run a game developer nonprofit in Montreal, and one of our discord members and event regulars shared this paper with me on generating building interiors.

Once I'm finished work for the day, I plan on trying to implement it in Unity (since that's where most of my proc gen work goes to die), but I wanted to share it with everyone here as an interesting take on interior generation based on parameters like building areas.

I would love to be able to one day generate a city, all the way down to explorable buildings, and this paper does seem promising for a good start at least.

If anyone has other resources or better processes, consider this post as an open invitation to be a resource dump :)
https://onlinelibrary.wiley.com/doi/10.1155/2010/624817

https://redd.it/1lwali8
@proceduralgeneration