Thanks.
The best explanation of the relationship between a topological and a mesh vertex I’ve found so far comes from @RIL in this post:
For anyone who is interested, here is a recursive method, I ended up using to find all mesh vertices and faces which fall within a radius of a given point:
public static void FindConnectedVertices(int mVertex)
{
Stack<int> verticesToCheck = new Stack<int>();
HashSet<int> visitedTVertices = new HashSet<int>();
// Local variables
var _topologyVertices = Brush.initialMesh.TopologyVertices;
var _meshVertices = Brush.mesh.Vertices;
Point3d hitPoint = Brush.mesh.Vertices[mVertex];
var tVertex = Brush.initialMesh.TopologyVertices.TopologyVertexIndex(mVertex);
verticesToCheck.Push(tVertex);
while (verticesToCheck.Count > 0)
{
var currentTVertex = verticesToCheck.Pop();
if (visitedTVertices.Contains(currentTVertex))
continue;
visitedTVertices.Add(currentTVertex);
var mVertices = _topologyVertices.MeshVertexIndices(currentTVertex);
var _point = _meshVertices[mVertices[0]];
double distance = hitPoint.DistanceToSquared(_point);
if (distance <= Brush.radiusSquared)
{
foreach (var mV in mVertices) // One topology vertex can contain multiple mesh vertices.
{
Brush.cursorVertices.Add(mV, _meshVertices[mV]);
Brush.cursorFaces.Add(mV, _topologyVertices.ConnectedFaces(currentTVertex));
}
var connectedTVertices = _topologyVertices.ConnectedTopologyVertices(currentTVertex);
foreach (var tV in connectedTVertices) // Mark connected topology vertices to check later
verticesToCheck.Push(tV);
}
}
}
This way I can update normals of selected faces and vertices without recalculating these for the entire mesh. Now, I’m down to 15ms for each draw call of the 450k quad test mesh. That’s 66 FPS - more than enough to keep things interactive and so much faster than what I initially had.
EDIT: Replaced the recursive method with a while loop to prevent stack overflow exceptions.
To answer the original question: in my testing the by far fastest way to display Mesh Wires is to use OpenGL. We can reuse buffers used for drawing the shaded triangles and switch to line display. It’s also a good idea to slightly offset the wires along vertex normals to prevent Z-fighting.
Is it also possible to apply paint locally to VertexColors and change the Faces color?
The main idea is to apply the mask. I am currently implementing this through e.Display.DrawMeshShaded and then e.Display.DrawMeshFalseColors Because I draw two versions at the same time. The rendering time increases almost twice. I am considering the possibility of using ghgl, I would appreciate it if you would share your decision. @stevebaer@mrhe@kitjmv
In fact, using **ghgl** mainly serves as an example of how to implement it in Rhino with C#. But your exact question would actually be “how to implement it with **OpenGL**”, because that’s what ghgl is really about.
And on that point, it’s essential first and foremost to know how to code and to understand how **OpenGL** and **GLSL shaders** work. From there, it becomes fairly straightforward to use OpenGL shaders to draw a mesh with a different color assigned to each vertex of the mesh.
I have already solved this problem. And I managed to achieve a mask rendering speed on a mesh with 1 million vertices in 5 milliseconds. used DrawMeshShaded(Mesh mesh, DisplayMaterial material, int faceIndices); but there are still some issues with the process of transferring the Transform mesh to replace the starting mesh. for the GetPointOnMesh function
ChangeMesh 43,9928 ms //OnMouseMove+m_down = true;
Final 40,2366 ms //OnMouseUp
GetPoint 1611,069 ms //OnMouseMove+m_down = false;
GetPoint 0,04 ms //OnMouseMove+m_down = false;
Perhaps the problem is that when I start using the new Mesh instead of the old one, a complete recalculation occurs for use. Rhino.Geometry.Intersect.Intersection ? @kitjmv@mrhe@stevebaer
Yes, each time you update the mesh, Rhino will rebuild its acceleration sctructure used for raycasting which is used by Rhino.Geometry.Intersect.Intersection. This is relatively slow. Doing this on every mouse move will kill your perfomance.
It’s difficult to help you and know exactly what’s going on, but here’s what I can state with some confidence:
Your CPU is fast enough (even if, like mine, it’s a 6-year-old computer).
Looping (foreach) over 1,000,000 vertices in C# is slow, but not nearly as catastrophic as one might imagine.
Transferring 1,000,000 vertices from Rhino’s native C++ library to C# (or from C# back to C++) is often slower than just storing the 1,000,000 vertices in a C# variable and performing the loop (foreach).
Transferring 1,000,000 vertices from C++ or C# to GPU memory is very often slower than all the above.
Currently, my main problem is that I am updating the mesh for use. Intersection.MeshRay, which takes a lot of time to update the calculation Intersection . GetPoint 1611,069 ms,
If you want to implement truly interactive mesh sculpting, you’d need to move away from Intersection.MeshRay and Mesh.PointAt.
As mentioned in my previous post - each time you update the Rhino.Geometry.Mesh it will be marked as dirty and any subsequent call to these methods will force a rebuild of the underlying acceleration structure which will kill performance.
An alternative I used with quite some success was porting the whole logic to a custom mesh library, and using OpenGL to display the underlying vertex and index buffers which is what Rhino does under the hood anyway.
While it works, this approach requires quite a bit of low-level hacks into the DisplayPipeline. It is only truly supported on Windows, and Rhino 9 is moving to D3D so I’m not even sure whether it will still be possible.
Having said that, if you want to explore this path, your best bet is to dissect the ghgl repo. It has a lot of unnecessary complexity for your needs, but it is open source and - when simplified - does exactly what you need: display triangles on screen regardles of where they came from. Once you’ll get that set up, you can then experiment with various raycasting libraries (Embree is great, but there are others too).
AFAIK, R9 will still support OGL, similarly to how R8 supports .NET Core8 & .NET45
But fundamentally it is about bypassing the DisplayPipeline and updating the underlying geometry buffers directly on the GPU. We will be able to do this with D3D albeit the exact code will have to change.