ProBuilderMesh.setVertices() - Object in the scene doesn't refresh until I manually interact with it

I’m trying to do something fairly simple: I want to move some vertices of a ProBuilderMesh in an editor script. This seems to be simple, but I’m finding that after doing so, the mesh either doesn’t visually update in the editor, or it updates and looks completely broken until I manually interact with its vertices.

First, here’s the code I’m using:

public static void SnapProBuilderNearSnappedToGrid()
{
    var currentObject = Selection.activeGameObject;
    if (currentObject == null)
    {
        Debug.LogWarning("No Object is selected.");
        return;
    }
    var proBuilderMesh = currentObject.GetComponent<ProBuilderMesh>();
    if (proBuilderMesh == null)
    {
        Debug.LogWarning("Current object has no ProBuilderMesh component.");
        return;
    }

    var vertices = proBuilderMesh.GetVertices();
    foreach (var vert in vertices)
    {
        vert.position += Vector3.one * 0.05f;
    }
    proBuilderMesh.SetVertices(vertices);
    //ProBuilderEditor.Refresh(vertexCountChanged: false);
    //proBuilderMesh.Refresh();

}

In this script, just to test things out, I’m simply moving the verts a small distance. Here’s a random shape I’ll run this script on:

After running it, nothing looks like it changed in the editor. But if I deselect and reselect the object, I’ll see its vertices have moved, but the editor is still showing the faces in the wrong position:

If I select one of those vertices, and move it, all the faces instantly return to where they belong. But I don’t want to have to manually interact with the object every time I run a script on it.

Okay. So I uncomment the line of code above ProBuilderEditor.Refresh(vertexCountChanged: false);, as I saw that as a suggestion in another thread, but that doesn’t change the result.

So, instead, I uncomment the line proBuilderMesh.Refresh(); That still doesn’t cause the object to display properly, and now it emits three errors to console:

Mesh.uv is out of bounds. The supplied array needs to be the same size as the Mesh.vertices array.
Mesh.normals is out of bounds. The supplied array needs to be the same size as the Mesh.vertices array.
Mesh.tangents is out of bounds. The supplied array needs to be the same size as the Mesh.vertices array.

I’ve checked, and the object has the correct number of all these things, so I don’t understand why it’s giving errors. I’m not changing the number of vertices.

So, in short, no matter what I do, after I call SetVertices, the object doesn’t refresh properly in the scene view until I edit it with one of the Probuilder scene tools. How can I correctly set the vertices in code, and have it all look correct in the editor after? Thanks.

Hi @dgoyette, I’ve looked at your code and all you were missing was proBuilderMesh.ToMesh(); just before doing the refresh. Here’s the updated code:

 public static void SnapProBuilderNearSnappedToGrid()
    {
        var currentObject = Selection.activeGameObject;
        if (currentObject == null)
        {
            Debug.LogWarning("No Object is selected.");
            return;
        }
        var proBuilderMesh = currentObject.GetComponent<ProBuilderMesh>();
        if (proBuilderMesh == null)
        {
            Debug.LogWarning("Current object has no ProBuilderMesh component.");
            return;
        }

        var vertices = proBuilderMesh.GetVertices();
        foreach (var vert in vertices)
        {
            vert.position += Vector3.one * 0.05f;
        }
        proBuilderMesh.SetVertices(vertices);
        proBuilderMesh.ToMesh();  // <- missing piece
        proBuilderMesh.Refresh();
    }

In addition, ProBuilder’s package samples include “Runtime Examples” that you might find helpful when looking for more examples on how to edit meshes via API.

Thanks very much. That indeed does the trick for me. I’ll take a look at the sample project in future. I guess I wasn’t aware of it.

One small thing to mention about the code above: There’s one additional optional thing to do afterwards, which is to call ProBuilderEditor.Refresh();. This isn’t necessary if the ProBuilder window is closed. But if the ProBuilder window is open, and you have that object selected, the editor’s edges won’t change when the vertices are moved. Here’s the above code, running without ProBuilderEditor.Refresh();

Before:

After:

So the final code ends up being:

var currentObject = Selection.activeGameObject;
if (currentObject == null)
{
    Debug.LogWarning("No Object is selected.");
    return;
}
var proBuilderMesh = currentObject.GetComponent<ProBuilderMesh>();
if (proBuilderMesh == null)
{
    Debug.LogWarning("Current object has no ProBuilderMesh component.");
    return;
}

var vertices = proBuilderMesh.GetVertices();
foreach (var vert in vertices)
{
    vert.position += Vector3.one * 0.05f;
}
proBuilderMesh.SetVertices(vertices);
proBuilderMesh.ToMesh();
proBuilderMesh.Refresh();
ProBuilderEditor.Refresh();

This will move the verts, and refresh the Editor so they appear where they should.

Again, I appreciate the quick assistance.

1 Like

Nice catch on that detail! And glad to hear it’s working now - don’t forget to mark the thread as resolved if it’s fixed.