2
\$\begingroup\$

I am trying to add some ores on my map using Perlin noise. The problem is sometimes Perlin noise does not produce enough values above the threshold, causing the amount of one ore is much lesser than the others.

In Factorio they somehow managed to keep the amounts of each ore are within a certain range during map generation. How can I achieve a similar behavior?

Edit:

Right now I am using scale, octaves, persistence, lacunarity, offset and threshold to generate a Perlin noise map, then just checking if the value at a coordinate is within the range of the threshold, if yes, then mark the pixel at that position with a specific color.

Currently the results look like this: enter image description here

The first problem is sometimes, for example, blue regions are super rare, like there are only 2 or 3 over the whole map. Another problem is there could be many unwanted little scatters around the map and I am unable to control them. How can I fix them?

PS: One type in a cell, binary presence and fixed quantity.

\$\endgroup\$
5
  • 2
    \$\begingroup\$ There are a couple good articles about the map generation in Factorio in their development blog. 258 specifically talks about how they generate resource spots. \$\endgroup\$
    – Philipp
    Oct 26, 2023 at 12:17
  • 2
    \$\begingroup\$ It would help if you describe the steps your taking &/or an example of the output. There's typically lots of ways to tune procedural generation, but without knowing more specifics, we're essentially guessing about the how you're using Perlin noise to generate your maps. We're also guessing about what sort of results you need. Can a cell location have multiple types of ore? Is the presence of ore binary (meaning it either has or or doesn't) or can a cell have a varying quantity of ore? \$\endgroup\$
    – Pikalek
    Oct 26, 2023 at 14:07
  • \$\begingroup\$ "there could be many little scatters around the map" -> It's not clear if you have that right now and want it gone, or don't have that now and want to. \$\endgroup\$
    – Philipp
    Oct 27, 2023 at 6:40
  • \$\begingroup\$ Sorry for the unclear description. I have edited the problem. \$\endgroup\$
    – silkmoon18
    Oct 27, 2023 at 8:31
  • \$\begingroup\$ For the little scatters, you may be interested in Cellular_automaton. If the rules are suitable, it will remove or merge the little scatters within a few iterations. \$\endgroup\$
    – Mangata
    Oct 27, 2023 at 19:45

2 Answers 2

3
\$\begingroup\$

Here's one way to use noise to generate a one type in a cell, binary presence resource map.

The first step is to generate site locations for the resources. There's a variety of ways to do this. The specific methodology is a balance between what type of distribution you want, how performant the code needs to be and how much complexity you want to deal with. Point generation details are beyond the scope of what I'm going to cover in detail here. I often favor a Poisson disc distribution, but for the purposes of illustration, I'm using a filtered uniform random distribution - basically it's rand & I randomized a few times until I got something that wasn't too clumpy. If you want to know more about point generation, I suggest researching some of our other posts on the topic followed by posting your own questions if needed.

A key point to mention - this step is pivotal in getting the desired amount of resources. I'm going to demonstrate using the colors red, blue and yellow to indicate different resources and decided red is about 50% less common than yellow or blue.

After generating the site locations, the next step is to generate a Voronoi diagram. Here's an illustration showing the sites, and color coded regions of the Voronoi:

color coded Voronoi

The next step is to build an intermediate layer that maps out the influence of each site. To do that, we select some radius \$r\$ and for each site, generate an area of influence with values of \$1 - \frac{d}{r}\$ where \$d\$ is the distance for the site. Visually, the influence map looks like this:

influence layer

The next step is to generate the noise layer. As with point generation, I'm not going to go into a lot of details. But based on your comments concerning small single pixel areas of resource, I suggest using a rather smooth looking noise & keep in mind that it may take some trial and error to hone in on what you're looking for. Here's an image of the noise I used:

noise layer

Both layers should have values from 0 to 1; if not, normalize your data. Then we combine the layers using the color burn operation:

  • invert the noise layer
  • divide by the influence layer
  • invert the result

Mathematically, the value for each \$x,y\$ coordinate location is: $$1-\frac{1-n_{x,y}}{i_{x,y}}$$

Graphically we get this:

color burned result

Again, the result should have values from 0 to 1. Applying a threshold function will convert the result to have values of 0 or 1. Mathematically, examine each coordinate location and if it's below the cutoff assign it a value 0; otherwise assign it a value of 1. This is another place where you can potentially tune the quantity of resources; the following animation shows how the resource area change as I adjust the threshold:

threshold adjustments

A more complex model might dynamically adjust the threshold to each resource type in order to more or less of a resource as needed. For simplicity, I applied the same threshold to all the resources. Here's the final result as a color coded map:

final result

There's rarely a one size fits all solution to procedural generation. You will likely need to experiment to get results that work well for your specific game. For instance, if smoothing out your noise doesn't reduce the unwanted little scatters, you will need to add a post processing step to remove them. However, using the approach here, any small scatters should be near a much large concentration of the same resource, so you might find that it works for you as a feature. For instance if I use this noise:

rough noise

I get this instead:

resources with nearby scatters

\$\endgroup\$
1
  • \$\begingroup\$ Thank you so much. I finally used Poisson disc distribution to get points and domain warp to distort the regions to get my resulted map. \$\endgroup\$
    – silkmoon18
    Oct 31, 2023 at 22:16
2
\$\begingroup\$

If you want "One type in a cell, binary presence and fixed quantity", then using a noise pattern is probably not the right tool for the job.

A far more straight-forward method would be to do this for every resource node you want to have in a cell:

  1. Pick a random spot within the cell
  2. Evaluate if the spot is suitable for placing this resource there, and if not, reroll until it is (up to a reasonable maximum amount of retries, so you don't end up in an infinite loop in cases where there aren't any suitable spots in the cell)
  3. Place a resource region with the desired quantity there.
\$\endgroup\$
6
  • 1
    \$\begingroup\$ How do I determine the shape of the regions? I just read this blog factorio.com/blog/post/fff-258 from factorio, it mentions they are adding noises to circles to make them into non-circular regions, but I am not sure how they do this. \$\endgroup\$
    – silkmoon18
    Oct 27, 2023 at 10:32
  • 1
    \$\begingroup\$ Domain warping would be one way to do that. I show an example here with a rectangle, but the technique is basically the same with a circle: take your sample point, use it to generate some coherent noise, then add that noise to the sample point before checking if the resulting sum is within the cluster radius of the cluster center. \$\endgroup\$
    – DMGregory
    Oct 27, 2023 at 11:12
  • \$\begingroup\$ @silkmoon18 There are several ways to do that, and which ones are appropriate depends on your exact requirements how you want the shapes to look. You might want to post a new question for this. \$\endgroup\$
    – Philipp
    Oct 27, 2023 at 11:24
  • \$\begingroup\$ @DMGregory Your example looks pretty nice. Would you like to share a sample code of how the shape is distorted? \$\endgroup\$
    – silkmoon18
    Oct 28, 2023 at 2:24
  • 1
    \$\begingroup\$ Nope, other folks have written great articles on Domain Warping you can refer to, and Pikalek's answer also shows a version of this. \$\endgroup\$
    – DMGregory
    Oct 28, 2023 at 2:29

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .