SketchUp Receive: Huge performance improvements with just two lines of code!

TLDR; I can reduce a large receive operation from hours to seconds by simply modifying a couple lines in: “./speckle-connector/src/speckle_objects/geometry/mesh.rb”

replace:

entities.add_faces_from_mesh(native_mesh, smooth_flags, material, material)
added_faces = entities.grep(Sketchup::Face).last(native_mesh.polygons.length)

with:

mesh_group = entities.add_group
mesh_group.entities.fill_from_mesh(native_mesh, true, smooth_flags, material, material)
added_faces = mesh_group.entities.grep(Sketchup::Face)

The reason this helps:

  1. speckle should always be putting new meshes in separate groups because otherwise it’s going to be killing itself trying to merge/combine faces with faces added in previous steps.
  2. using “fill_from_mesh” is far more performant than “add_faces_from_mesh”.

There is a little more cleanup needed for production:

  1. Now that we group geometry, we should probably apply layers and attributes to the group and not the faces.
  2. Another benefit of using groups is we can do the CleanUp right after creating the entities. I recommend adding in erase_lonely_edges after merge_coplanar_faces.
  3. While we’re taking about how meshes are converted, I disagree with the smoothing flags setting; we should default to “HIDE_BASED_ON_INDEX” (1) in almost all conditions. AUTO_SOFTEN would be a rare exception.

Let me know if or where I can help with this. I can provide my modified scripts if needed.
You can get my mesh script here: mesh.rb

3 Likes

Hey @miketalbott ,

Welcome to the community! Feel free to Introduce yourself :person_gesturing_ok: to the community if you want to! :grinning:

I loved the title of this thread! @oguzhankoral will take a look at this. If they come with the benefits you mentioned, they can definitely be merged.

2 Likes

Hi Bilal,

It’s long overdue for me to get involved. I’ve been a speckle fan/user for over two years.

I’m an architect turned software developer turned computational designer and 10 years ago I was building ruby scripts for SketchUp fulltime. I’m a little rusty now but really wanted the SketchUp connector to be more usable for the scale and complexity of projects that I work on.

For my tests, I’ve been using the following model that is a parametric model from grasshopper, not too complex but enough to freeze up the SketchUp connector:
Utah Housing Facade Model

I just re-ran the receive with the current unmodified connector and got:

==== Converting to Native executed in 4250.207 sec ====

(1 hour and 10 minutes)

and on my modified branch:

==== Converting to Native executed in 36.163 sec ====

(that’s a 117x improvement!)

and if I turn off merge coplanar faces:

==== Converting to Native executed in 11.778 sec ====

And I think it will be even better on big Revit files.

I provided the link to the “mesh.rb” in the first post. but here’s the cleanup script with erase lonely edges added in:
clean_up.rb

And you need to remove the cleanup from receive_objects.rb:
receive_objects.rb

There is still room for improvement. The one case where you wouldn’t want every mesh in a group is for objects made up of sub-meshes that have different materials on different faces. I don’t know enough about the speckle object model but maybe we can detect and handle that condition. Also, it would be nice to add in auto-smoothing based on angle between faces. And finally, the “fill_from_mesh” has a “weld_vertices” option that I don’t understand yet.

Hope this is all helpful.

5 Likes

Hey @miketalbott,

Thanks for your input, the results are quite promising! :rocket:

Putting every generated mesh into its group eliminates geometrical checks for the application to find face-edge-planarity relationships, and bypass an exponential check when we keep adding more meshes to the document. This is a wise move in some cases because it might have massive performance improvement as you pointed out.

On the other hand, since every mesh lies in its group, it will become a bit cumbersome to modify objects if we want to. AFAIK -smoothing the faces will become unlikely since the edges are in different scopes (groups). These edges don’t have any relationship (because bypassed) even if they overlap with neighbor’s face edge.

But in some cases, users might not be interested at all in modifying faces or smoothing their edges. What I would suggest here is to have them both with another option.

We also have a ticket to partly replace the usage of meshes in SketchUp connector with Face and Polygon conversions on receive to have more native conversions instead of using meshes heavily to create Sketchup::Face objects.

More input is welcome, and this topic is worth discussing :raised_hands:

Hi @oguzhankoral,

Definitely worth the discussion.

If there are valid scenarios for a “sticky” import, then I’d say an option would be a good way to go. I might suggest you default to grouped because it’s faster and less destructive. ie a user can easily explode a group if needed but you can’t unexplode it.

Your sphere test case is interesting to me because I’m not aware of the scenario where we would be sending a sphere with each quad separated into its own mesh. I see it two ways: 1. Either the sphere represents not well formed data, and it should have been joined/combined by the user or the speckle send. Or 2. It is intensional and the user wants separate quads and we should return those separate as intended.

Either way, we shouldn’t be modifying the data as it was sent, if it’s separate keep it separate. If it’s smoothed and combined keep it that way. When you do the “sticky” import you are modifying the data.

Regarding the face, edge, polygon approach. Seems like a good idea when the data would support it. Mesh still might be the best choice in some scenarios. Just remember to use the SketchUp EntityBuilder class to construct the geometry as using the .add_ methods will be super slow.

2 Likes

Hey @miketalbott,

I just wanted to update you that we are still reviewing the implications of your proposal. We haven’t forgotten about you. After conducting some benchmarking, we identified a bottleneck in our current implementation related to multi-meshes (which your model is full of, see image for an example). When comparing the two methods with single mesh objects, they perform very similarly.

At the moment, we are investigating how your proposal would impact object tracking and updating behavior. We will either accept it as is or explore alternative solutions to address the multi-mesh issue.

Here’s a comparison of current implementation and your proposal. As you can see, they perform very similar when it comes to models from Revit, Tekla, Archicad etc.

1 Like