# Terrain Determination in Perlin Noise Texture in Godot 4.2.1

4.2.1

### Question

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 by checking the noise values for a set of “checkpoints” and applying a set of rules . 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)]
)

# compute 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 offsets = _terrain_gradient.offsets
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)
``````

and the noise texture’s underlying parameters are loaded from this resource:

``````[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

``````

Now, instead of a representation of the point type, I get results that don’t correspond to what I see on the texture. When plotting these points using the color in the gradient corresponding to their values, I often find blue ocean points on green grassland portions or coastline points showing up in ocean parts. I’d be grateful for any pointers to what I might be doing wrong here.

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