How to modify an already existing mesh? How to set vertices of a surface?

Godot Version

        for (int s = 0; s < o_groundMesh.GetSurfaceCount(); s++)
        {
            Godot.Collections.Array surfaceData =  o_groundMesh.SurfaceGetArrays(s);
            Vector3[] borderVerts = (Vector3[])surfaceData[0]; 
            
            for (int o = 0; o < borderVerts.Length; o++)
            {
                if (borderVerts[o].X < 0)
                {
                    borderVerts[o].X -= halfAdditionX;
                }
                else if (borderVerts[o].X > 0)
                {
                    borderVerts[o].X += halfAdditionX;
                }
            }
            
            o_groundMesh.SurfaceSetArrays(s)[0] = borderVerts; //my attempt
        }

Question

I want to change the vertices as shown, but the mesh isn’t updating the changes (since is not applied). In Unity, it was a matter of setting the mesh = to another mesh, but since Godot has surfaces am a little confused on how to do this. Reading the documentation doesn’t help either.

I think since you are using the same mesh instance you need to commit the surface change with this function. add_surface_from_arrays.

can you please post a bit of code? I tried this o_groundMesh.AddSurfaceFromArrays(s);

Are you using an array mesh?

arr_mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arrays)
            var arrMesh = new ArrayMesh();
            var arrays = new Godot.Collections.Array();
            arrays.Resize((int)Mesh.ArrayType.Max);
            
        for (int s = 0; s < o_groundMesh.GetSurfaceCount(); s++)
        {
            Godot.Collections.Array surfaceData =  o_groundMesh.SurfaceGetArrays(s);
            Vector3[] borderVerts = (Vector3[])surfaceData[0]; 
        
            for (int o = 0; o < borderVerts.Length; o++)
            {
                if (borderVerts[o].X < 0)
                {
                    borderVerts[o].X -= halfAdditionX;
                }
                else if (borderVerts[o].X > 0)
                {
                borderVerts[o].X += halfAdditionX;
                }
            }
                         
            arrays[(int)Mesh.ArrayType.Vertex] = borderVerts;
            arrMesh.AddSurfaceFromArrays(Mesh.PrimitiveType.Triangles, arrays);
        }
        
        o_groundMesh = arrMesh;   //MeshInstance3D _o_ground = GetNode<MeshInstance3D>("./o_ground");
    o_groundMesh = _o_ground.Mesh;

Btw I didn’t match any names from your code it may not work for you. And you may not need to make a new mesh instance.

What is this class of the mesh?

     // Excuse my ignorance: I don't understand your question (I think you refer to it being a Mesh?)... however, I think it's working now, since the mesh apparently changed, but it doesn't look how it is supposed to look like and I suspect that it might be because is interpreting a single..triangle? Could you help me with this?
             var arrMesh = new ArrayMesh();
            var arrays = new Godot.Collections.Array();
            arrays.Resize((int)Mesh.ArrayType.Max);
            
        for (int s = 0; s < o_groundMesh.GetSurfaceCount(); s++)
        {
            Godot.Collections.Array surfaceData =  o_groundMesh.SurfaceGetArrays(s);
            Vector3[] borderVerts = (Vector3[])surfaceData[0]; 
        
            for (int o = 0; o < borderVerts.Length; o++)
            {
                if (borderVerts[o].X < 0)
                {
                    borderVerts[o].X -= halfAdditionX;
                }
                else if (borderVerts[o].X > 0)
                {
                    borderVerts[o].X += halfAdditionX;
                }
            }
                         
            arrays[(int)Mesh.ArrayType.Vertex] = borderVerts;
            arrMesh.AddSurfaceFromArrays(Mesh.PrimitiveType.Triangles, arrays);
        }
           
        MeshInstance3D _o_ground = GetNode<MeshInstance3D>("./o_ground");
        _o_ground.Mesh = arrMesh;

if it helps, am just moving everything the same amount to the right, so am sure the problem is the way am doing it, since it only shows a triangle…

I tried playing around with what you were doing, not sure what you were doing with the x value but in this example I made little bumps.

I’m not sure the normal map is correct after doing the regen. (not sure it did anything at all)

@tool
extends Node3D


func _ready():
	var o_groundMesh : PlaneMesh = PlaneMesh.new()
	o_groundMesh.set_subdivide_depth(12)
	o_groundMesh.set_subdivide_width(12)
	var mesh_arrays : Array = o_groundMesh.get_mesh_arrays()
	var vert_array : PackedVector3Array = mesh_arrays[Mesh.ARRAY_VERTEX]
	for vidx in range( vert_array.size() ) :
		if randi_range(0,1): # random move
			vert_array[vidx].y -= 0.1
		else:
			vert_array[vidx].y += 0.1
	#mesh_arrays[Mesh.ARRAY_TANGENT].clear()
	#mesh_arrays[Mesh.ARRAY_NORMAL].clear()
	
	var arr_mesh: = ArrayMesh.new()
	arr_mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, mesh_arrays)
	#arr_mesh.regen_normal_maps()
	$MeshInstance3D.mesh = arr_mesh

image

Thanks for helping me. Am trying to implement that code, but in c# (mostly with the help of chatGPT), since I don’t know GDScript, and am getting an error in the packedVector3Array and Randi. At any case, what you are doing seems to be right. Could you share a minimalistic simplified code (c#) of this? If you can’t, at least erase those lines, since I can more or less read GDScript anyway (also the vertArray line shows an error)

_o_groundMesh.SubdivideDepth = 12;
_o_groundMesh.SubdivideWidth = 12;
Godot.Collections.Array meshArrays = _o_groundMesh.GetMeshArrays();
Vector3 vertArray = (Vector3)meshArrays[(int)Mesh.ArrayType.Vertex];
for (int t = 0; t < vertArray.Length; t++)
{
vertArray[t].X += 2f; //example
}

        meshArrays[(int)Mesh.ArrayType.Vertex] = vertArray;
        
        var arr_mesh = new ArrayMesh();
        arr_mesh.AddSurfaceFromArrays(Mesh.PrimitiveType.Triangles, meshArrays);
        GetNode<MeshInstance3D>("./o_ground").Mesh = arr_mesh;

//Now is working! is moving to the right. However, it is shrinking. Any ideas why?

I finally figured out why. It’s because, by default, the size of the plane is smaller. However. then everything goes back to the original problem, since my ground is a 3D mesh and your entire code doesn’t work for that. Is there any way to work around this?

var arr_mesh = new ArrayMesh();  // I finally found the way:
for (int s = 0; s < o_groundMesh.GetSurfaceCount(); s++) {
  Godot.Collections.Array meshArrays = o_groundMesh.SurfaceGetArrays(s);
  Vector3[] vertArray = (Vector3[]) meshArrays[(int) Mesh.ArrayType.Vertex];
  for (int t = 0; t < vertArray.Length; t++) {
    if (vertArray[t].X < 0) {
      vertArray[t].X -=
          orig_halfAdditionX;  // Add or subtract from original size, otherwise
                               // it only works for a frame because o_groundMesh
                               // is constant from _Ready()
    } else if (vertArray[t].X > 0) {
      vertArray[t].X += orig_halfAdditionX;
    }
  }

  meshArrays[(int) Mesh.ArrayType.Vertex] = vertArray;
  arr_mesh.AddSurfaceFromArrays(Mesh.PrimitiveType.Triangles, meshArrays);
}
GetNode<MeshInstance3D>("./o_ground").Mesh = arr_mesh;