• Godot Help2D
  • Open simplex noise - convert grey values to 0 or 1

Good day,

I want to improve the way how i make a procedural map from open simplex noise. When i print the min and max values, i have got 0.556863 and 0.568627.

I'd like to have something like this:

around 0 = sea tile
around 0.25 = grass tile
around 0.75 = rocks tile
around 1 = mountain tile

It will more helpful to have this kind of scale i think. My question is: how can i get that from a grey color ? How can i "convert" this without increasing the contrast like i can do in Gimp, for exemple ?

  • TwistedMind
    If you want an approximate rescale to fit 0-1, you could do something like this:

    var result = clamp((value-0.5)*scale+0.5,0,1)

    where value is the grey value from the pixel map and scale is some number that scales the value to hit 0 and 1 range, with the clamp then making sure it doesn't go outside of that range.

    If you know the exact min and max of the entire pixel map, you could precisely scale it to 0,1 range using:

    var result = range_lerp(value, mini, maxi, 0, 1)

    range_lerp takes a value in one range and remaps it to a different range (in this case 0,1).

You will have to find the error in your algorithm and figure out why all values are so close together. Or post the code so we are able to have a look at it.

Something like this may be realized with different textures for grass, rocks and mountains, and applying the respective texture values in a shader depending on the value of the noise texture. Leave a range where you blend between the textures.

This is sometimes called texture splatting, and is the simplest solution I know of for this kind of problem. Well, apart from just assigning a colour or picking one from a colour ramp texture depending on height value.

I'd recommend a separate water shader for close-to-0 values, and maybe a beach/sand texture for the shores.

Here my actual code:

func makeMap():
	var noise = OpenSimplexNoise.new()
        var test = []
	noise.seed = 1012
	noise.octaves = 2
	noise.period = 32
	noise.persistence = 0.8
	var seamlessNoise = noise.get_seamless_image(97)
	seamlessNoise.lock()

	for cellx in range(0, 97):
		for celly in range(0, 97):
			var pixelMap = seamlessNoise.get_pixel(cellx, celly) # RVBA value
			var mapCell = pixelMap[0]*3.5
			test.append(pixelMap[0])
			
			if mapCell < 1.80:
				set_cell(cellx, celly, 11) # water

			elif mapCell >= 1.80 and mapCell < 2:
				set_cell(cellx, celly, 5) # grass

			elif mapCell >= 2.1 and mapCell < 2.12:
				set_cell(cellx, celly, 7) # rock
			elif mapCell >= 2.2 and mapCell < 4:
				set_cell(cellx, celly, 6) # moutain
			else:
				set_cell(cellx, celly, 5) # grass
	
	print(min(test[0], test[test.size()-1]), ' ', max(test[0], test[test.size()-1]))

So those are the min and max of the first value and the last value. Not of the whole range. These two are close together because of the "seamless" character.

I see. i have a bad use of min and max.

I need to know, to be sure, the min and max value of the seamlless image generated, if i do this,

var maxi = test[0]
 var mini = test[0]
	
	for i in test:
		if i < mini:
			mini = i
		elif i > maxi:
			maxi = i
	
	print(mini, ' ', maxi)

Now is it correct ? I have 0.262745 and 0.682353. My question remain the same.

In Perlin noise at least, the value never reaches 0 or 1, I found one implementation that multiplies the noise value by 1.4142 to get closer, but I think that was a range of -1 to 1. You might also want to lower your period.

Also
var seamlessNoise = noise.get_seamless_image(97)
seamlessNoise.lock()
These lines shouldn't be necessary

    I need a generated texture to be seamless, because i will copy the map around the initial map. These lines are necessary.

    In Perlin noise at least, the value never reaches 0 or 1...

    I understand. That's means i can't do any improvement about the scale...

      Erich_L
      There's an interesting article that goes into the mathematics behind finding the min and max of original Perlin Noise: https://digitalfreepen.com/2017/06/20/range-perlin-noise.html
      The end point being the range is -sqrt(N/4) to sqrt(N/4) where N is the dimensions.
      So for 2D noise, the min is -0.707 and the max is 0.707.
      Multiplying that by 1.4142 makes it -1 to 1.

      I don't know how much (if at all) simplex varies. Plus Godot doesn't use Ken Perlin's Simplex noise, it's actually Open Simplex which works just differently enough to avoid Ken's patents.
      (Damn patents!)

        TwistedMind
        If you want an approximate rescale to fit 0-1, you could do something like this:

        var result = clamp((value-0.5)*scale+0.5,0,1)

        where value is the grey value from the pixel map and scale is some number that scales the value to hit 0 and 1 range, with the clamp then making sure it doesn't go outside of that range.

        If you know the exact min and max of the entire pixel map, you could precisely scale it to 0,1 range using:

        var result = range_lerp(value, mini, maxi, 0, 1)

        range_lerp takes a value in one range and remaps it to a different range (in this case 0,1).

        The seamlessness might suffer when scaling.

        Kojack yep that looks like the website I got it from. I'd wager that any perlin variant will also not hit 0 or 1.