Search code examples
2dmeshgodotprocedural-generation

MeshDataTool.commit_to_surface calls don't preserve vertex colors?


A Godot newbie here, so please be gentle.

This short code snippet reveals my problem: I'm able to modify vertex colors of a mesh and present them just fine with a create_from_surface & commit_to_surface pair.

But if I read the mesh data again with another create_from_surface and instantly return it with commit_to_surface without doing any other changes, the vertex color data is lost, and the mesh returns to its default color.

Is this how it's supposed to work? And if so, do I need to save the color data vertex by vertex to a temporary array and then read it back again to preserve the color data? Seems terribly inefficient, or am I missing something?

Thanks in advance!

extends MeshInstance2D
var mdt = MeshDataTool.new()
# Called when the node enters the scene tree for the first time.
func _ready():
    mdt.create_from_surface(mesh, 0)
    var vertex_count = mdt.get_vertex_count()
    for i in range(vertex_count):
        mdt.set_vertex_color(i, Color((mdt.get_vertex(i).x),0,1))
    mdt.commit_to_surface(mesh) # Mesh shows as having a gradient from blue to purple
    mdt.create_from_surface(mesh, 0) # If I un-comment the next line, mesh shows as white 
    #mdt.commit_to_surface(mesh)
    #... 

Edit: Ivy's more elegant solution fixed this right away, thank you! Next, I'll remove the additional debugging creates and commits, and start applying my actual game logic.

extends MeshInstance2D
var mdt = MeshDataTool.new()
# Called when the node enters the scene tree for the first time.
func _ready():
    mdt.create_from_surface(mesh, 0)
    var vertex_count = mdt.get_vertex_count()
    for i in range(vertex_count):
        mdt.set_vertex_color(i, Color((mdt.get_vertex(i).x),0,1))
    mesh.clear_surfaces()
    mdt.commit_to_surface(mesh) # Mesh shows as having a gradient from blue to purple
    mdt.create_from_surface(mesh, 0) 
    mesh.clear_surfaces()
    mdt.commit_to_surface(mesh) # The gradient persists, yay!
    #... 

Solution

  • Great find! This looks agonizing.

    It appears that the MeshDataTool creates a new surface on your mesh when you commit to the surface. So you need to pull to the second surface (index 1) in your second create_from_surface. If you change your code to the following, it should work:

    extends MeshInstance2D
    var mdt = MeshDataTool.new()
    # Called when the node enters the scene tree for the first time.
    func _ready():
        mdt.create_from_surface(mesh, 0)
        var vertex_count = mdt.get_vertex_count()
        for i in range(vertex_count):
            mdt.set_vertex_color(i, Color((mdt.get_vertex(i).x),0,1))
        mdt.commit_to_surface(mesh) # Mesh shows as having a gradient from blue to purple
        mdt.create_from_surface(mesh, 1) # If I un-comment the next line, mesh shows as white 
        #mdt.commit_to_surface(mesh)
        #... 
    

    A more elegant way would be to run clear_surfaces before each commit_to_surface call.

    Better documentation should definitely exist for this. I didn't see any note of this unusual behavior anywhere. Might be worth opening up an Issue on the Godot GitHub page.