- Home /
Procedural Tree Placement using perlin noise
I have made a procedural terrain generation in unity using some tutorials but i cant figure out how i can randomly place trees on my terrain and i couldnt find anything on the internet. So how can i randomly place trees using perlin noise on a procedural terrain?
Answer by ShadyProductions · Feb 14, 2018 at 06:40 PM
Usually what I do is i loop over my map that I have in memory and if i'm on a tile that can inhabit a tree i put a random chance to put a tree there, After that algorithm is done the map has random trees but its kinda ugly, So I use something called Cellular Automata to remove all tree's that aren't grouped (all tiles that don't have more than 3 neighbors of same tree). After that you end up with dense forests of tree's, depending on your chances.
Here is an example (without rendering):
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace Assets.Scripts
{
public class MapGeneration : MonoBehaviour
{
private const int mapSize = 25;
private int[,] map;
private void Start()
{
// Setup the array
map = new int[mapSize, mapSize];
// Populate map with some random types between 1 - 4
PopulateMap();
// will replace all type 2 with type 3
// if the type 2 tile does not have more than 2 neighbors of the same type.
// This will give you a grouped effect of the given type
// parameters: tile, replacement, minAlive
ApplyCellularAutomationMin(2, 3, 2);
// rendering of the map
// .....
}
private void PopulateMap()
{
System.Random rand = new System.Random();
for (int x=0; x < mapSize; x++)
{
for (int y = 0; y < mapSize; y++)
{
map[x, y] = rand.Next(5); // Set a random type between 1 - 4
}
}
}
private int GetTile(int x, int y)
{
// Get the tile type or -1 if outside of bounds
return (x > map.GetUpperBound(0) || y > map.GetUpperBound(1) || x < 0 || y < 0) ? -1 : map[x, y];
}
private IEnumerable<int> GetNeighbors(int x, int y)
{
// Each tile has 8 neighbors
var neighbors = new int[8];
// Get each neighbor based on the tile position x, y
neighbors[0] = GetTile(x - 1, y);
neighbors[1] = GetTile(x, y - 1);
neighbors[2] = GetTile(x - 1, y - 1);
neighbors[3] = GetTile(x + 1, y);
neighbors[4] = GetTile(x, y + 1);
neighbors[5] = GetTile(x + 1, y + 1);
neighbors[6] = GetTile(x - 1, y + 1);
neighbors[7] = GetTile(x + 1, y - 1);
// Exclude -1 tiles because those are unexisting ones returned by GetTile
return neighbors.Where(f => f != -1);
}
private void ApplyCellularAutomationMin(int tile, int replacementTile, int minAlive)
{
// Perform twice to cleanup residue of automation
for (int i = 0; i < 2; i++)
{
for (int x = 0; x < map.GetLength(0); x++)
{
for (int y = 0; y < map.GetLength(1); y++)
{
// Get only the neighbors where the type is the given tile.
var neighbors = GetNeighbors(x,y).Where(f => f == tile);
// If there are not enough alive, then replace the tile.
if (neighbors.Count() < minAlive)
{
map[x, y] = replacementTile;
}
}
}
}
}
}
}
Your answer
Follow this Question
Related Questions
Multiple Cars not working 1 Answer
Unexpected period length with Unity Mathematics pnoise method 0 Answers
Mesh generation issue (C#) 1 Answer
How to add erosion to terrain on runtime 0 Answers