Fastest way to display Mesh Wires

That doesn’t sound right. You shouldn’t need face normals. They are only used for flat shade drawing

This is how it looks with and without face normals:

Guess I was wrong; Jeff must be using face normals for some part of his shading alogrithm. In any case, computing face normals is not very computationally expensive.

It might be faster if you compute the face normals first. But you would need to have a large mesh to see the difference.

Ok, I’ve got a proof-of-concept running but the GLShader version is approx. 50-75% slower than DrawMeshShaded from the DisplayConduit.

GLSL:

DrawMeshShaded:

After compiling the shader once, I’m updating the mesh on every frame like this:

        public static void UpdateMesh(Rhino.Geometry.Mesh mesh)
        {
            _model.ClearData();
            _model.GetUniformsAndAttributes(1).AddMesh(mesh);
        }

Is this overhead to be expected, or just a side effect of a hacked implementation of mine? If it’s the former, then I’ll revert back to what I had previously. If it’s the latter, then I’d appreciate any advice on how to speed things up.

Hello @mrhe

I advise you to create your own array and buffer and use OpenGL class functions directly.
Look, at each iteration a new buffer is created if you use UniformsAndAttributes.AddMesh(mesh)

Following your advice @kitjmv, I dug a bit deeper into the GLSLViewModel, and found a way to reuse the TriangleIndexBuffer. Now, on each update, I create a new GLSLViewModel.MeshData object from the updated mesh and copy the buffer over from the previous one:

        public static void UpdateMesh(Rhino.Geometry.Mesh mesh)
        {
            var _m = new GLSLViewModel.MeshData(mesh);
            _m.TriangleIndexBuffer = _model.GetUniformsAndAttributes(1)._meshes[0].TriangleIndexBuffer;
            _model.GetUniformsAndAttributes(1)._meshes[0] = _m;
        }

This gets us straight to the following statement in the Draw method:

Which results in a 75% speed increase over the previous implementation and 25% increase over DrawMeshShaded from a DisplayConduit!

Now, can we access the vertex data of the GLSLViewModel.MeshData object directly? Don’t see any ways to do it from here:
https://github.com/mcneel/ghgl/blob/823765a9f78dc86e08e38389c2b9514886fa1750/src/GLSLViewModel.cs#L532-L544

Here are some initial tests with a working matcap implementation. Thanks for open-sourcing the GHGL code @stevebaer! I wouldn’t have known how to approach this without it:

And a short video of one of the materials in action:

Looks like you have a gopher problem :slight_smile:

If you wanted to update a portion of an existing vertex buffer object in OpenGL, you would use glBufferSubData. That would be quicker than creating and uploading an entire new mesh, but it may not be worth it given you seem to be getting decent speeds now.
https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glBufferSubData.xhtml

Thanks @stevebaer!

Following your suggestion, I was able to reduce the drawing speed by another 40%. Now, on my 450k quads test mesh, I’m getting consistent update speeds of approx. 40ms. That’s about 25 FPS. Given, that some of the time is spent on finding the cursor-mesh intersection, drawing the cursor, and creating copies for undo operations, this is a great result.

I ended up manipulating the array buffer directly and only replacing the modified vertices like so:

        public static void ReplaceVertex(int location, Rhino.Geometry.Point3f vertex)
        {
            IntPtr _location = new IntPtr(3 * sizeof(float) * location);
            IntPtr _size = new IntPtr(3 * sizeof(float));

            var handle = System.Runtime.InteropServices.GCHandle.Alloc(vertex, System.Runtime.InteropServices.GCHandleType.Pinned);
            IntPtr _dataPointer = handle.AddrOfPinnedObject();

            OpenGL.glBindBuffer(OpenGL.GL_ARRAY_BUFFER, _model.GetUniformsAndAttributes(0)._meshes[0].VertexVbo);
            OpenGL.glBufferSubData(OpenGL.GL_ARRAY_BUFFER, _location, _size, _dataPointer);
            handle.Free();
        }

Same procedure needs to be repeated for vertex normals with the exception, that we’re dealing with a Vector3f and targeting the NormalVbo.

Btw. I extended your implementation to include the glBufferSubData method. Do you want me to create a PR to add it to GhGL as well?

I investigated this further and it turns out, that computing normals for the entire mesh on every draw call is actually quite expensive. In my case, it takes more than 50% of the total time elapsed.

Is there a way of calculating normals just for selected vertices/faces?
I tried doing it manually, but calling the MeshVertexList.GetVertexFaces method for a few hundred vertices is very slow (about a second just to retrieve the faces indices).

Edit: Calculating normals actually takes closer to 80-85% of the entire time (35 out of 45 ms for my test mesh).

Are you updating the Mesh instance itself between every draw call? I wouldn’t do that until the end of the dynamic updating operation. There is quite a bit of cache building when first calling a function like GetVertexFaces which really only needs to be done once on the initial mesh.

Makes sense. I kinda have to update the mesh in the current implementation to calculate the normals.

But it’s a good idea to keep an unmodified copy of the initial mesh to use it for subsequent GetVertexFaces queries.

I believe that calculating the normals is going to build the cache as well so unless you completely do everything yourself with the set of data you are manipulating you aren’t going to get a performance boost by keeping the old mesh around.

[EDIT] I was wrong; the cache is not built when computing these normals

1 Like

Nah, copying the initial mesh and querying it for vertex connections doesn’t really make a difference.
My initial idea was to create a dictionary to store the values for later use but analyzing the entire mesh (450k quads) like so:

for (int i = 0; i < mesh.Vertices.Count; i++)
      mesh.Vertices.GetVertexFaces(i);

took almost 7 minutes to complete!
I thought that vertex-face connectivity is stored as a property, but it seems that vertices are not aware of which face they belong to and need to search for it each time.

As an alternative, I could use a RTree.CreateMeshFaceTree with a sphere search to find the affected faces.

I’m using one for vertices already and it updates very fast. Instead, I could look for faces, which store their vertices as A, B, C, D properties and work from there.

Ideally, though - if I can make a feature request for future versions of Rhino - it would be great for meshes to have better connectivity awareness. A half-edge structure or similar, with fast queries of connected vertices, edges and faces would be awesome. And, yes, I am aware of @DanielPiker’s Plankton but a native Rhinocommon implementation would certainly be appreciated.

Have you looked at the topological vertices on a mesh?

These represent all of the unique locations on a mesh and can consist of more than one MeshVertex.

The mesh topology data is the cache that I was referring to that is created when first queried on a mesh.

This makes a huge difference! Looping over the entire mesh takes 1 second:

            for (int i = 0; i < mesh.Vertices.Count; i++)
            {
                var topologyVertex = mesh.TopologyVertices.TopologyVertexIndex(i);
                var faces = mesh.TopologyVertices.ConnectedFaces(topologyVertex);
            }

And it makes sense to work on a copy of the initial mesh. For my specific application, the first query takes around 300 ms, but all subsequent ones are executed in around 1 ms. It’s still odd, that the GetVertexFaces() method is so slow, though.

There can be many mesh vertices for a single topological vertex. I would just walk through the list of topological vertices and get faces. Your code snippet is probably doing too much work.

Well, I have a list of mesh vertices highlighted by a brush and want to find which faces they belong to. Doesn’t it make sense to iterate over these and find the corresponding TopologyVertices?

Correct me if I’m wrong, but a topological vertex will only correspond to many vertices if the mesh is not welded properly, wouldn’t it? Otherwise, it should always be a one-to-one relationship.

The above code snippet was just a test to see how much faster this approach can be. This is what I actually do:

// Dictionary<int, Point3d> cursorVertices;

foreach(var kvp in cursorVertices)
{
    var topologyVertex = initialMesh.TopologyVertices.TopologyVertexIndex(kvp.Key);
    var faces = initialMesh.TopologyVertices.ConnectedFaces(topologyVertex);
 }

It is more common for there to be multiple vertices for a single topological vertex.