Edit mesh vertices without replacing the mesh object

Hey,

I’m trying to recreate basic mesh sculpting functionality similar to how Blender or zBrush work.

This potentially means moving a lot of vertices hence a very efficient pipeline is needed. I tried accessing the VertexPoint3fArray like so, but this changes the underlying geometry without updating the preview.

unsafe
            {
                using (var meshAccess = mesh.GetUnsafeLock(true))
                {
                    int arrayLength;
                    Point3f* points = meshAccess.VertexPoint3fArray(out arrayLength);
                    for (int i = 0; i < arrayLength; i++)
                    {
                        if (verticesCenter.ContainsKey(i))
                            points->Z += strength;
                        points++;
                    }
                    mesh.ReleaseUnsafeLock(meshAccess);
                }
            }
doc.Views.Redraw();

Note, how I can select the ‘invisible’ vertices, meaning that the mesh is being modified but not updated in the drawing pipeline:

I could copy the Mesh and replace the previous one with the modified geometry like this:

           Mesh _mesh = new Mesh();
           _mesh.CopyFrom(mesh);

           doc.Objects.Replace(id, _mesh);
           doc.Views.Redraw();

This works as expected but I’m wondering whether there is a way to avoid the copy/replace part to keep things as efficient as possible:

I realized, that it’s possible to replace the mesh with an updated version without copying it:

            foreach (var i in verticesCenter.Keys)
            {
                var p = mesh.Vertices[i];
                p.Z += strength;
                mesh.Vertices[i] = p;
            }

            doc.Objects.Replace(id, mesh);
            doc.Views.Redraw();

This works relatively smoothly with lower polygon counts (approx. 15k) but slows down significantly as soon as the polygon count increases to 25k+.

Any ideas on how to further optimize it?

Hello @mrhe

Have you made any progress on this point?

I asked a similar question, (but with different constraints) a few days ago.

The difference is that in my case the number of points changes.
Dale offered me the solution of not modifying the internal geometry of a RhinoObject. But use a Conduit instead.

This solution is not possible in my case, but maybe for you it is.
I haven’t tested it, but using a conduit is probably faster than modifying the RhinoDoc.Objects table on each iteration.

For example :
When you enter in sculpt mode, you create a conduit to display a copy of the mesh.
While sculpting, you make changes to this copy.
Once satisfied, the user commits the changes.
And this is where you replace the Mesh of your real RhinoObject.

Thanks @kitjmv,

yeah, I ended up doing exactly what you described:

  1. On enter sculpting mode → hide the mesh RhinoObject from the document and copy it to a custom DisplayConduit
  2. While sculpting → update the mesh in PostDrawObjects
  3. On end sculpting mode → unhide the original mesh in doc.Objects and replace it with the updated one

This seems to be very efficient when it comes to time spent drawing geometry. Having done some more thorough testing with a Stopwatch, I was able to identify other parts of my sculpting logic, which need more optimization. The display part takes less than 1 ms to complete.

1 Like

An alternative solution using the OpenGL pipeline came up in another thread. It is roughly twice as fast as using the DisplayConduit but requires much more work to customize the code from the GhGL component: