# Terrain Determination in Perlin Noise Texture in Godot 4.2.1

For my Grand Strategy game, I am looking to use maps generated by Godot's FastNoiseLite implementation of Perlin noise. While generating the texture for the map was straightforward, I've already spent weeks to figure out a way to determine the overall terrain type of Voronoi cells drawn on the map. For this, I implemented a "Star Check" to spread points on the borders of each cell and from those border points to the respective site points, like so:

func star_check(cell_center: Vector2, n_steps: int=10) -> Array:
var terrain_types: Array
var polygon: Array = _polygon
var n_points = polygon.size()
var checkpoints: Array
var lines: Array

# read in lines as arrays of [start, end point, distance]
for i in range(n_points):
var last_index: int = n_points - 1
var line: Array
match i:
last_index:
line = [polygon[i],polygon[0],polygon[i].distance_to(polygon[0])]
_:
line = [polygon[i],polygon[i + 1],polygon[i].distance_to(polygon[i + 1])]

lines.append(line)

var border_checkpoints: Array
# compute ceckpoints along edges of points
for line in lines:
var line_points: Array = []
var step_size: int = floor(line[2] / n_steps)
var from: Vector2 = line[0]
var to: Vector2 = line[1]

for k in range(n_steps):
var point: Vector2 = from + k * step_size * from.direction_to(to)
line_points.append(point)

border_checkpoints.append_array(line_points)

var center_lines: Array = border_checkpoints.map(func(p):

return [p, cell_center, p.distance_to(cell_center)]
)

# conpute center checkpoints from border points
var center_checkpoints: Array
for line in center_lines:
var line_points: Array = []
var step_size: int = floor(line[2] / n_steps)
var from: Vector2 = Vector2(line[0])
var to: Vector2 = Vector2(line[1])

for k in range(n_steps):
var point: Vector2 = from + k * step_size * from.direction_to(to)
line_points.append(point)

center_checkpoints.append_array(line_points)

border_checkpoints.append_array(center_checkpoints)

checkpoints = border_checkpoints.filter(func(p): return Geometry2D.is_point_in_polygon(p, _polygon)) #only use points in voronoi site
check_points = checkpoints #internal class_variable

terrain_types = checkpoints.map(func(p): return _evaluate_point_type(p))
check_point_values = terrain_types #internal class_variables

return terrain_types


Determining the terrain type of a point is done in _evaluate_point_type using enums to represent their position in the (non-normalized and centered) NoiseTexture's color ramp:

enum Terrains {DEEP_OCEAN, SHALLOW_OCEAN, COAST, GRASSLAND, MOUNTAIN_BOTTOM, MOUNTAIN_MEDIUM, MOUNTAIN_TOP}

func _evaluate_point_type(point: Vector2) -> int:
var point_value = ((_map_noise.get_noise_2dv(point) + 1) * 0.5) #translate to [0,1] for offset matching
var type: int = -1
var last_index: int = len(offsets) - 1
for i in range(len(offsets)): #find corresponding offset
match i:
0:
if point_value < offsets[Terrains.SHALLOW_OCEAN]: #everything below first non-zero offset
type = Terrains.DEEP_OCEAN
last_index:
if point_value > offsets[Terrains.MOUNTAIN_TOP]: # everything above highest offset
type = Terrains.MOUNTAIN_TOP
_:
if point_value >= offsets[i] and point_value < offsets[i + 1]:
type = i

return type



The noise gradient is loaded from a saved Gradient resource that corresponds to the color ramp used by the noise texture:

[gd_resource type="Gradient" format=3 uid="uid://wrob2ye40vuu"]

[resource]
interpolation_mode = 1
offsets = PackedFloat32Array(0, 0.481236, 0.505519, 0.516556, 0.626932, 0.660044, 0.679912)
colors = PackedColorArray(0, 0, 1, 1, 0.299985, 0.470862, 1, 1, 0.657183, 0.508635, 0.167871, 1, 0.280679, 0.399257, 0.108318, 1, 0.333719, 0.196772, 0.0853799, 1, 0.396025, 0.358924, 0.223805, 1, 1, 1, 1, 1)


Now, instead of a representation of the point type, I get weird results, such as ocean points on grassland areas of the texture, or coastline points on ocean portions of the noise texture. I'd be grateful for any pointers to what I might be doing wrong here.

EDIT: Here is the Noise Resource used in texture generation:

[gd_resource type="FastNoiseLite" format=3 uid="uid://davh6t1gndhdm"]

[resource]
noise_type = 3
frequency = 0.002
fractal_lacunarity = 2.575
domain_warp_type = 1
domain_warp_amplitude = 29.055



Example of point on "mountain" portion of gradient being evaluated as an ocean point (circle is larger than point for visibility)

• It would help if you could edit to include an example of the input noise texture & maybe the output as well. I've found that proc gen of this type is very dependent on properly tuned input. Folks working through your code won't necessarily get the same results if they're not applying it to that same data as you're using. Similarly, sample output would help spot potential errors in the logic. Apr 1 at 15:02
• Thanks for the advice. I'll add the contents of the godot resource file containing the parameters to set it up in Godot Apr 1 at 15:21