I have been trying to convert the code in C# on this thread to gdscript, but I can’t do it.
public override void _Ready(){
var meshData = this.meshInstance3D.Mesh.SurfaceGetArrays(0);
var positions = meshData[(int)Mesh.ArrayType.Vertex].AsVector3Array();
GD.Print(positions.Length);
for(var index=0;index<positions.Length;index++){
positions[index].Y *= Mathf.Sin(positions[index].Y*50);
}
meshData[(int)Mesh.ArrayType.Vertex] = positions;
var newMesh = new ArrayMesh();
newMesh.AddSurfaceFromArrays(Mesh.PrimitiveType.Triangles,meshData);
this.meshInstance3D.Mesh = newMesh;
}
My code can’t seem to replace the verts in the ArrayMesh. Here is what I have:
func _create_mesh_array() -> Array:
if true:
var output_mesh : ArrayMesh
output_mesh = ArrayMesh.new()
# This makes a copy of the prim as an ArrayMesh
output_mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, prim.get_mesh_arrays())
var pos : PackedVector3Array = output_mesh.surface_get_arrays(0)[Mesh.ARRAY_VERTEX]
print(pos)
# This messes with the verts
for i in range(pos.size()):
var vert = pos[i]
vert += Vector3(0,1,0)
pos[i] = vert
print(pos) # verify the verts have changed
# Now struggle in vain to get it all back into the ArrayMesh...?
output_mesh.surface_get_arrays(0)[Mesh.ARRAY_VERTEX] = pos # ?
# This should return the new data - one day
return output_mesh.surface_get_arrays(0)
You can’t replace values inside the Arrays like this. That will do nothing.
First, because Mesh.ARRAY_VERTEX is a PackedVectorArray which is a COW Vector array that does copy on write. You are never editing the “original” array when you assign a new value because it creates a copy on change.
Second, changing the arrays from surface_get_arrays() does nothing at all for the mesh as those are just data arrays. They have zero ties to your actual mesh, it is just data.
You need to clear the old mesh surface(s) and create a new surface with add_surface_from_arrays() using the changed arrays.
If you already know very well what you are doing and how mesh arrays function you can use the RenderingServer API to update surface regions instead of clearing and creating the entire surface but that is far more advanced and error-prone.
Hi, thanks. How do I clear a surface by index? (I mean using ArrayMesh)
In the C# code, there’s this meshData[(int)Mesh.ArrayType.Vertex] = positions; which seems to replace the data in that array. Is this just C# magic, vs the COW you mentioned?
Mesh surface arrays are a normal Godot Array that is passed by reference with multiple PackedXYZArray which are all COW on the inside.
Sure when you only have one user of the array you don’t notice but if e.g. anything would use the vertices PackedVector3Array directly and you change a vertex all other users of that cow array would bail out from that change and keep their old array data copy.
You cant clear individual mesh surfaces, you either clear all or none.
The reason for this is because internally a rendering mesh is just a giant data array with a certain stride / offset so you can’t just start to stitch something randomly in the middle as it would invalidate most of the data basically requiring to recreat a new mesh anyway.
Okay, I get your general message. I will look at the other tools in gdscript for mesh hacking. Still a bit confused by that C# code though, but meh. Can’t solve all the mysteries!
I am not sure what should be confusing here. MeshDataTool is a convenience helper class to build arrays to create mesh surfaces. All convenience costs more because you pay for all the extra steps behind the scene.
The words say “altering arrays directly using ArrayMesh”. It’s not unclear, but it does seem wrong, from what you explained before.
I’m just a mesh code-editing newb right now and there’s a lot of contradicting info (like in the reference post in the OP), not angry with you or anything!