Hi, I am back again with a little problem.

I am trying to create a mesh through code, but for some reason some edges are created between two vertices that shouldn't be connected together.

Ultimately my goal is to attempt to create a terrain from a heightmap image (in png format most likely) and then create rivers and such in a similar way.

Here is what I mean in the form of an image:

And here is the code that I use to create the quads and triangles: Am I missing something or is it simply due to the order I create the vertices in? I create the vertices in a clockwise order.

extends MeshInstance

var tmpMesh = Mesh.new()
var vertices = PoolVector3Array()
var UVs = PoolVector2Array()
var mat = SpatialMaterial.new()
var color = Color(0.023438, 0.908447, 1)

func create_triangle(x, y, z):
	vertices.push_back(Vector3(x,z,y))
	vertices.push_back(Vector3(x+1,z,y))
	vertices.push_back(Vector3(x+1,z,y+1))

	UVs.push_back(Vector2(x,y))
	UVs.push_back(Vector2(x,y+1))
	UVs.push_back(Vector2(x+1,y+1))

func create_triangle_opposite(x, y, z):
	vertices.push_back(Vector3(x,z,y+1))
	vertices.push_back(Vector3(x,z,y))
	vertices.push_back(Vector3(x+1,z,y+1))

	UVs.push_back(Vector2(x,y))
	UVs.push_back(Vector2(x,y+1))
	UVs.push_back(Vector2(x+1,y+1))

func create_quad(x, y, z):
	create_triangle(x,y,z)
	create_triangle_opposite(x,y,z)

func _ready():
	create_quad(0,0,0)
	create_quad(1,0,0)
	create_quad(1,1,0)
	create_quad(0,1,0)
	mat.albedo_color = color

	var st = SurfaceTool.new()
	st.begin(Mesh.PRIMITIVE_LINE_LOOP)
	st.set_material(mat)

	for v in vertices.size():
		st.add_color(color)
		st.add_uv(UVs[v])
		st.add_vertex(vertices[v])

	st.commit(tmpMesh)

	mesh = tmpMesh

Thank you in advance for your help!

Here's my generate quad function that works for reference:

func generate_quad(positionIn : Vector3, size : Vector2):
	
	var bottomRight = Vector3(positionIn.x, solveForY(positionIn.x, positionIn.z), positionIn.z)
	
	var topLeft = Vector3(positionIn.x + size.x, solveForY(positionIn.x + size.x, positionIn.z + size.y), positionIn.z + size.y)
	
	var topRight = Vector3(bottomRight.x, solveForY(positionIn.x, positionIn.z + size.y), topLeft.z)

	var bottomLeft = Vector3(topLeft.x, solveForY(positionIn.x + size.x, positionIn.z), bottomRight.z)

	
	vertices.push_back(topRight)
	vertices.push_back(bottomRight)
	vertices.push_back(bottomLeft)
	
	vertices.push_back(topRight)
	vertices.push_back(bottomLeft)
	vertices.push_back(topLeft)
	
	uvs.push_back(Vector2(0,0))
	uvs.push_back(Vector2(0,1))
	uvs.push_back(Vector2(1,1))
	
	uvs.push_back(Vector2(0,0))
	uvs.push_back(Vector2(0,1))
	uvs.push_back(Vector2(1,1))

My solve for y function finds terrain height at x,z. Notice by doing the whole quad together you don't have to calculate a few points more than twice... but the side points will unfortunately still be calculated again on the edges with other quads, resulting in a ton of extra vertices.

Oh I see what you mean, yeah right now I am basically creating some vertices on the same point for no reason where I could instead simply create the full quad right away.

I was thinking about it similarly to how I would do it on unreal in the past where all meshes had to be triangles to prevent potential problems in the future.

Huge thank you for the huge help. I will try the code right away and reply back if it works or if I encounter another problem :)

So far by adding an indexing to the vertices, it seems to work better, although there is still one incorrect edge that I can see at least.

And with a little bit of debugging, the indexes are correct, I just need to figure out how to make each set of index connect independently rather than try to connect every single one of them.

I am unsure what to try next, but I will keep working on it until it works.

Thank you for the reference code! It's super useful to make sure I am not messing up the variables. It makes the debugging a lot easier to do :)

I change part of my code to this:

func create_quad(x, y, z):
	vertices.push_back(Vector3(x,z,y)) # first vertice
	vertices.push_back(Vector3(x+1,z,y)) # second vertice
	vertices.push_back(Vector3(x+1,z,y+1)) # third vertice
	vertices.push_back(Vector3(x,z,y+1)) # fourth vertice

	UVs.push_back(Vector2(x,y))
	UVs.push_back(Vector2(x,y+1))
	UVs.push_back(Vector2(x+1,y+1))
	UVs.push_back(Vector2(x+1,y))

	verticeIndexes.push_back(4*quadsAmount) # first vertice index
	verticeIndexes.push_back(4*quadsAmount+1) # second vertice index
	verticeIndexes.push_back(4*quadsAmount+2) # third vertice index

	verticeIndexes.push_back(4*quadsAmount)
	verticeIndexes.push_back(4*quadsAmount+2)
	verticeIndexes.push_back(4*quadsAmount+3) # fourth vertice index

	quadsAmount += 1

func commit_quad(st, tempMesh):
	print(verticeIndexes)
	for v in vertices.size():
		st.add_color(color)
		st.add_uv(UVs[v])
		st.add_vertex(vertices[v])

	for i in verticeIndexes:
		st.add_index(i)

	st.commit(tempMesh)
	vertices = clearArray

Apparently changing my ready function made the lines appear correctly. So apparently, in the code I had to add the vertices in a clockwise order, but in the mesh I had to add the quads in a counterclockwise order instead. I probably did something wrong, but I'm happy that it works so far :D.

Now it's time to make a 100x100 and try to optimize that monster of a code when it innevitably creates way too much vertices and fails again haha. But I do have a way to fix that already. I just need to change the array from a vector3 array to a simple array or dictionary and then add some check up to see if the point already exists or not, then I need to account for that change in the indexing most likely.

Here's the little change to the _ready function if anyone is interested :)

func _ready():
	mat.albedo_color = color

	var st = SurfaceTool.new()
	st.begin(Mesh.PRIMITIVE_LINE_LOOP)
	st.set_material(mat)

	create_quad(0, 0, 0)
	create_quad(1, 1, 0)
	create_quad(1, 0, 0)
	create_quad(0, 1, 0)
	commit_quad(st, tmpMesh)

	mesh = tmpMesh

Huge thank you again for the help!

Small update to the code I posted. It works super nicely already, I just need to connect the quads together now so I can generate terrains and such rather than having a square mess.

The solution to the problem I had was in the way I indexed the quad's vertices. I used part of this page's code when they create a cube. I only needed the dictionary variable along with the function that populated it. Then I adapted my code in create_quad to use the function and made sure the indices were added in the correct order.

What it looks like currently after applying a random value to the quad's height position on a 100x100 grid. I also moved the camera a little bit compared to the first few images so I could see the quads a little easier.

extends MeshInstance

var tmpMesh = Mesh.new()
var vertices = PoolVector3Array()
var verticeArray = []
var clearArray = PoolVector3Array()
var verticeIndices = []
var UVs = PoolVector2Array()
var mat = SpatialMaterial.new()
var color = Color(0, 0.976562, 1)
var quadsAmount = 0

var dictionary_check_quad_vertices = {}

func _add_or_get_vertex_from_array(vertex):
	if dictionary_check_quad_vertices.has(vertex) == true:
		return dictionary_check_quad_vertices[vertex]

	else:
		verticeArray.append(vertex)

		dictionary_check_quad_vertices[vertex] = verticeArray.size()-1
		return verticeArray.size()-1

func create_quad(x = 0, y = 0, z = 0):
	var point1 = _add_or_get_vertex_from_array(Vector3(x,z,y)) # first vertice
	var point2 = _add_or_get_vertex_from_array(Vector3(x+1,z,y)) # second vertice
	var point3 = _add_or_get_vertex_from_array(Vector3(x+1,z,y+1)) # third vertice
	var point4 = _add_or_get_vertex_from_array(Vector3(x,z,y+1)) # fourth vertice
	vertices = verticeArray

	verticeIndices.append(point1)
	verticeIndices.append(point2)
	verticeIndices.append(point3)


	verticeIndices.append(point1)
	verticeIndices.append(point3)
	verticeIndices.append(point4)

	#UVs.push_back(Vector2(x,y))
	#UVs.push_back(Vector2(x,y+1))
	#UVs.push_back(Vector2(x+1,y+1))
	#UVs.push_back(Vector2(x+1,y))

	quadsAmount += 1

func commit_quad(st, tempMesh):
	for v in vertices.size():
		st.add_color(color)
		#st.add_uv(UVs[v])
		st.add_vertex(vertices[v])
		#st.add_index(v)

	for i in verticeIndices:
		st.add_index(i)

	st.commit(tempMesh)
	vertices = clearArray

func _ready():
	mat.albedo_color = color

	var st = SurfaceTool.new()
	st.begin(Mesh.PRIMITIVE_TRIANGLES)
	st.set_material(mat)

	var mapSize = Vector2(100,100)

	for y in mapSize.y:
		for x in mapSize.x:
			create_quad(x-mapSize.x/2, y-mapSize.y/2)
	commit_quad(st, tmpMesh)

	mesh = tmpMesh

Once I get the quads to stay connected correctly, I will reply again with the code incase it could be of help to others :)

a year later