Rhino 8, WIP extremely slow - due to results of MeshSplit

I’m posting this because it may help someone else who has Rhino become almost unresponsive.

Using MeshSplit to split a group of 7 meshes resulted in Rhino becoming almost unresponsive, because the split increased the number of meshes by a factor of 20,000. Joining the split meshes into 2 meshes restored the responsiveness but scrambled the photo texturing.

The original “mesh” was actually a group of 7 meshes with about 10 million faces in total and were photo textured. The group of meshes were created by Metashape and exported as a .obj file. I imported the meshes into Rhino, oriented and scaled them, and saved as .3dm file. I’ve opened and used that file in both Rhino 8 and Rhino 9 WIP. Both remain responsive.

I ungrouped the meshes and used MeshSplit to split the meshes with a planar surface. The result is 140427 meshes.

I grouped the meshes after splitting into two sets and saved as .3dm file. Open the file with the split meshes in Rhino 8 or Rhino 9 WIP and the result is almost unusable. Even for operations not involving the meshes, such as turning on/off layers which do not contain the meshes and simple geometry creation Rhino frequently acts as if it is locked up for ten seconds or longer. HWMoniter shows the CPU very active during these periods.

I used Join on the two groups of meshes to create 2 meshes. Unfortunately the mesh texture was completely scrambled, though it did restore the responsiveness of Rhino.

Can we get an example of this? I can benchmark it here.

@scottd I found the meshs described above and recreatedobject used to split them. Tested them in BETA (9.0.26202.12303, 2026-07-21) and the behavior described above was reproduced

File size is about 750MB for the original mesh and 1GB for the split and grouped mesh (though not joined). They are confidential (should not be available to the public on the internet though no problem with you having them for internal purposes only). Where can I upload the file to?

My guess is the fragmentation of the 7 meshes into over 140 thousand meshes is the cause of the slowness. Would you like the file with the unsplit meshes, the file with the split meshes, or files with both?

I would like it before they are split and then a definition I can use to split it. Then I can benchmark both and we can profile the process. That would be awesome.

@scottd Where can I upload the file to?

Upload here, please add a link to the thread in the comments.

https://www.rhino3d.com/upload

@scottd @Japhy File uploaded.
MeshSplit the mesh in layer “Mesh Hull 10M” using the plane in layer “Center Plane”.

Thanks for the file David, i was able to benchmark here in the latest BETA (9.0.26203).

The 7 meshes (9.65M faces) split in ~97 seconds into 26,701 meshes — every disjoint piece becomes its own object. After the split each viewport redraw takes ~1 second even for operations that don’t touch the meshes (adding a single point), which lines up with what you are seeing — your full model fragmented to 140k meshes, roughly 5x this example.

The object count itself is the bottleneck, which is also why Join restored responsiveness. The texture scrambling after Join looks like a separate issue — can you post a small example of that? A couple of the textured pieces before and after Join would do.

https://mcneel.myjetbrains.com/youtrack/issue/RH-97201 RH-97201 MeshSplit explodes disjoint meshes into thousands of objects

@japhy When I split the 7 meshes (which are grouped) with 9,651,819 polygons I get 140,427 meshes, not 26,701. Perhaps I have an option set differently somewhere.

Command line history:

Command: MeshSplit
Select objects to split ( Tolerance=Auto CoplanarFaces=Keep CreateNgons=Yes DiscardUnsplitMeshes=Yes WithEachOther )
Select objects to split. Press Enter when done ( Tolerance=Auto CoplanarFaces=Keep CreateNgons=Yes DiscardUnsplitMeshes=Yes WithEachOther )
Select cutting objects ( CoplanarFaces=Keep CreateNgons=Yes DiscardUnsplitMeshes=Yes )
Select cutting objects. Press Enter when done ( CoplanarFaces=Keep CreateNgons=Yes DiscardUnsplitMeshes=Yes )
There are groups among the objects to be split. Some objects might be grouped after splitting.

Your results differ from mine for the same mesh. The mesh in that file is
the “full model”. There are no additional meshes.

I need to be able to split the mesh without “every disjoint piece becomes its own object.”

I don’t think a “small example” would have the mesh scrambling. I suspect it is a function of the sizes of the original seven meshes and the amount of texturing.

The meshes in Metashape as a single textured mesh. Metashape exported it as 1 .obj file, 1 .mtl file and 6 .jpg files. (I can upload those files if they would be useful.)

The mesh files were imported into Rhino 9 WIP and the result was 7 textured mesh objects. My experience is the numer of mesh objects created when import a single set of mesh files depends on the size/number of the texture files. My understanding, based on previous forum dicussions, is Rhino cannot have meshes with multiple texture images and therefore when importing such a mesh splits the mesh into multiple meshes, each with a single texture image. Therefore I doubt it is possible to Join the very large number of meshes into a single mesh without corrupting the texturing.

My bad, the layer loop kept overwriting the target variable, so it selected and split only the last of the 7 meshes. I’ll go through it again.

this script splits each mesh with the plane and rejoins the pieces per side, so 7 meshes become 14, each keeping its own texture.

#! python 3
# Split selected meshes with a planar surface, keeping each side of each
# mesh as ONE object (no disjoint-piece explosion, textures preserved).
# Workaround for https://mcneel.myjetbrains.com/youtrack/issue/RH-97201
import Rhino
import scriptcontext as sc

def main():
    go = Rhino.Input.Custom.GetObject()
    go.SetCommandPrompt("Select meshes to split")
    go.GeometryFilter = Rhino.DocObjects.ObjectType.Mesh
    go.GetMultiple(1, 0)
    if go.CommandResult() != Rhino.Commands.Result.Success:
        return
    refs = [go.Object(i) for i in range(go.ObjectCount)]

    gp = Rhino.Input.Custom.GetObject()
    gp.SetCommandPrompt("Select planar cutting surface")
    gp.GeometryFilter = Rhino.DocObjects.ObjectType.Surface
    gp.EnablePreSelect(False, True)
    gp.Get()
    if gp.CommandResult() != Rhino.Commands.Result.Success:
        return
    ok, plane = gp.Object(0).Surface().TryGetPlane()
    if not ok:
        print("Cutting surface is not planar")
        return

    for ref in refs:
        obj = ref.Object()
        pieces = obj.Geometry.Split(plane)
        if not pieces:
            print("No split on %s" % obj.Id)
            continue
        a = Rhino.Geometry.Mesh()
        b = Rhino.Geometry.Mesh()
        for p in pieces:
            (a if plane.DistanceTo(p.GetBoundingBox(False).Center) >= 0 else b).Append(p)
        for side in (a, b):
            if side.Faces.Count > 0:
                sc.doc.Objects.AddMesh(side, obj.Attributes.Duplicate())
        sc.doc.Objects.Delete(obj, True)
    sc.doc.Views.Redraw()

main()

Ran it on your file: same 140,427 internal pieces, but 14 objects out the other end in ~7 minutes, texture coordinates intact on all of them, and the file is fully responsive afterward (redraws back to instant).

Thank you!

I’m curious how the the texture coordinates remain intact, cutting the mesh with the plane would generate new faces & vertices. In my understanding, that should break the mapping?

@japhy Would you like a similar but smaller and non-confidential example to attach to the YT?

yes, Thank you!

cdordoni, note that i’m not a dev so muddling through things a bit myself. If it gets too technical i need to bring in a big brain

the texture coordinates on these meshes are explicit per-vertex data, baked in when the .obj was imported. They aren’t recomputed from a mapping projection.

When the intersector cuts a triangle, the original vertices keep their UVs as-is and each new vertex along the cut gets a UV interpolated from the corners of the triangle it sits in. The mesh just gains sample points, the mapping doesn’t move.

The scrambling earlier in the thread came from Join, not the split — each of these photogrammetry meshes carries its own texture image, and joining across them collapses everything to one object with one material, so most of the UVs end up pointing into the wrong image.

Here’s a small example — one textured mesh with 4 disjoint islands, and the same mesh after Mesh.Split with the plane (6 meshes out). The cut lands mid-checker on purpose, so any UV shift at the new vertices would be obvious. Texture is embedded in the file.
uv-split-example.3dm (405.2 KB)

per vertex, I get it!

Second example file uploaded. Non-confidential example. About one quarter the size of the original example. 3 meshes before splitting. 6668 meshes after splitting.

@Japhy posted RH-97201 and I worked on this during the week. Good news: we have a fix already. It’s quite pervasive, so we will see: it will need more tweaks especially with groups. These are coming probably this week in the BETA.

For this week, if you need to work on such large meshes, I suggest to remove groups and run this code in batches nonetheless.

@davidcockey RH-97201 is further fixed in this week’s BETA. Please let me know if you notice anything is still amiss.

@

@piac I tried splitting 6 large photo-textured meshes which were grouped in Rhino 9 BETA, 9.0.26237.15343
It seemed to work, and then Rhino closed. No error messages or anything.

I ungrouped the six meshes, selected the meshes, and then split them successfully.

Rhino 9 SR0 2026-8-25 (Rhino 9 BETA, 9.0.26237.15343, Git hash:master @ 96051fb40f8d55297d947c054b9d2f7c03d4bdeb)
License type: Commercial, build 2026-08-25
License details: Cloud Zoo
Expires on: 2026-10-09

Windows 11 (10.0.26100 SR0.0) or greater (Physical RAM: 64GB)
.NET 10.0.11

Computer platform: DESKTOP

Standard graphics configuration using DirectX
Primary display: NVIDIA GeForce RTX 2080 Ti (NVidia) Memory: 11GB, Driver date: 6-11-2026 (M-D-Y). DirectX(11)
> Accelerated graphics device with 4 adapter port(s)
- Windows Main Display attached to adapter port #0

Secondary graphics devices.
None found.

DirectX Settings
Safe mode: Off

OpenBLAS: OpenBLAS 0.3.30 DYNAMIC_ARCH NO_AFFINITY Haswell MAX_THREADS=64.

Rhino plugins that do not ship with Rhino
C:\Users\dcock\AppData\Roaming\McNeel\Rhinoceros\packages\9.0\ClippingBox\0.5.3\ClippingBox.rhp “ClippingBox” 0.5.3.0

Rhino plugins that ship with Rhino
C:\Program Files\Rhino 9 WIP\Plug-ins\Commands.rhp “Commands” 9.0.26237.15343
C:\Program Files\Rhino 9 WIP\Plug-ins\rdk.rhp “Renderer Development Kit”
C:\Program Files\Rhino 9 WIP\Plug-ins\3dxRhino.9.rhp “3DxRhino.9”
C:\Program Files\Rhino 9 WIP\Plug-ins\UpdatesAndStatistics\UpdatesAndStatistics.rhp “UpdatesAndStatistics” 9.0.26237.15343
C:\Program Files\Rhino 9 WIP\Plug-ins\RhinoRenderCycles.rhp “Rhino Render” 9.0.26237.15343
C:\Program Files\Rhino 9 WIP\Plug-ins\rdk_etoui.rhp “RDK_EtoUI” 9.0.26237.15343
C:\Users\dcock\AppData\Roaming\McNeel\Rhinoceros\packages\9.0\PanelingTools\2024.8.20.677\PanelingTools.rhp “PanelingTools”
C:\Program Files\Rhino 9 WIP\Plug-ins\NamedSnapshots.rhp “Snapshots”
C:\Program Files\Rhino 9 WIP\Plug-ins\MeshCommands.rhp “MeshCommands” 9.0.26237.15343
C:\Program Files\Rhino 9 WIP\Plug-ins\RhinoCycles.rhp “RhinoCycles” 9.0.26237.15343
C:\Program Files\Rhino 9 WIP\Plug-ins\Displacement.rhp “Displacement”
C:\Program Files\Rhino 9 WIP\Plug-ins\SectionTools.rhp “SectionTools”