Gradual beach at the border of map

Question

I’m trying to create a procedural mesh for the first time. I’d like the terrain to gradually slope down towards the edge of the map (if(island_mask==0):slight_smile: to form a sort of beach. I don’t know how to interpolate this. Thanks for the help already!

extends MeshInstance3D

@export var size := 60.0          # dimensione isola
@export var resolution := 500     # più basso = più low poly
@export var height := 7    # altezza massima

@export var noise_scale := 0.04

var noise := FastNoiseLite.new()

func _ready():
	noise.seed = randi()
	noise.frequency = noise_scale
	generate_terrain()




func generate_terrain():
	var plane := PlaneMesh.new()
	plane.size = Vector2(size, size)
	plane.subdivide_width = resolution
	plane.subdivide_depth = resolution
	var arrays := plane.get_mesh_arrays()
	var vertices: PackedVector3Array = arrays[ArrayMesh.ARRAY_VERTEX]
	var colors : PackedColorArray = []

	colors.resize(vertices.size())
	
	var cosaaa = 0
	
	
	for i in vertices.size():
		var v := vertices[i]
		
		# noise base
		var h := noise.get_noise_2d(v.x, v.z)

		# maschera per creare l'isola (abbassa i bordi)
		var dist := Vector2(v.x, v.z).length() / (size * 0.5)
		var island_mask :float = clamp(1.0 - dist, 0.0, 1.0)
		
		
		v.y = h * height * island_mask
		vertices[i] = v

		
		
		var height_percent = (v.y + 1.0) / (height + 1.0) 
		height_percent = clamp(height_percent, -1.0, 1.0)
		
		if(height_percent <= -0.01):
			
			colors[i]= Color(0.0, 0.221, 0.317, 1.0)
		elif (height_percent < 0.25):
			colors[i]= Color(0.319, 0.54, 0.25, 1.0)
		else:
			colors[i]= Color(1.0, 1.0, 1.0, 1.0)
		
		if(island_mask<0.2):
				colors[i]= Color(0.797, 0.608, 0.323, 1.0) #deep sea level
				v.y=-3
				vertices[i] = v
		
	
	arrays[ArrayMesh.ARRAY_VERTEX] = vertices
	arrays[ArrayMesh.ARRAY_COLOR] = colors

	var mesh := ArrayMesh.new()
	mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arrays)
	self.mesh = mesh
	

Calculate the 2D distance of the vertex from the map center (or from edge), sample a falloff curve with this distance as a parameter and multiply the vertex y with the sample value. For a falloff curve you can use a Curve resource.

I think I know what you’re trying to do.

I’m assuming generate_terrain() is a function that is used sparingly; once every time the terrain is initialized. If it’s not, and you need the function to run repeatedly, I’m not sure the following suggestion will work for you since it’s on the CPU.

If you wish to run this kind of stuff repeatedly, and fast, I suggest making use of compute shaders to utilize the GPU. Image processing operations – especially those using kernels – are not a great fit for the CPU because they require a large amount of repetitive operations which can be handled in parallel on the GPU.

That said, my initial suggestion would probably be to perform a set of operations on a copy of your island_mask such that edges in the mask produce a falloff rather than staying binary:

  1. Dilation
  2. Gaussian Blur

Original bitmask → dilation (sometimes called maximum) → gaussian blur

The dilation operation is first performed to prevent the binary edge from “growing” when blurring the mask. As such, care needs to be taken when selecting filter sizes for each operation. As an example, a blur size of 33 (i.e. a 33x33 kernel) requires a dilation of 16 steps (33 / 2 = 16.5, then round down).

Dilation is usually performed in steps instead of using large kernels because this kind of operation (dilation/erosion) often removes small blobs in the image – something often desired in other industry contexts.

This can then be used to add a y-displacement to the geometry via the use of this newly generated “texture”.


I hope you get the idea. Let me know if you have any questions.

1 Like