Converting SubD (4k faces) to Nurbs and Maintaining Topological Symmetry

Hi all,
I’m working on a system that takes a mesh with symmetric topology and turns it onto a smooth nurbs surface for export. When I convert a sub-d to nurbs it automatically packs the faces and I have no control over how this packing is done. It seems to attempt symmetry but fails to do so across the whole model even if its topologically and geometrically symmetrical. I was wondering if anyone knew of a good way to control face packing? I’m not opposed to writing code or editing save files – whatever it takes.

Original SubD

Packed Faces

Nurbs surface exported as Parasolid.


Splitting the object in half, delete one half, ToNurbs and mirror would be a workaround…

Splitting in half before converting to Nurbs won’t work in many cases since it will break continuity along the symmetry plane, unless all polygons touching that plane are perpendicular to it.

I think the ToNurbs command should check for symmetry before conversion and respect such symmetry, if it’s too hard to autodetect, it should at least have a symmetry option in the command to define a symmetry plane.


1 Like

@stevebaer @dale Is symmetry “hard” to autodetect, or just “slow”? Is it a function that could benefit from parallel processing - especially on a GPU with hundreds or thousands of cores?

I forgot, you’re right.

ToNurbs, then delete half of the object and mirror again would certainly work.

Hi @levib1 ,

There is no support for user-controlled face packing yet, neither from the UI nor the RhinoCommon SDK. It’s possible to manually set face packs in the C++ SDK, and later calls to ToNURBS will respect that packing if it is valid. You need to make a plugin to use the C++ SDK, and generating face packs manually is tedious and error-prone so I don’t think this is what you want to do.

Symmetrical face packing is tracked here: (non-public). I’ll move it up my list so it gets done sooner. The changes will go in v8.


For face packs that are spanning over the symmetry plane, you also need to trim the surface on a UV curve (_Split _Isocurve + delete one half), and shrink it (_ShrinkTrimmedSrf). After the mirror operation, the resulting pieces should be able to be merged back into a single NURBS (_MergeSrf). That will leave you with a couple of extra knots on the NURBS, depending on if they are close to extraordinary knots you should be able to delete them (_RemoveMultiKnot or _RemoveKnot)

1 Like

Not particularly hard to detect (as long as the user provides the reflection plane), a bit slow on very large SubDs because of the amount of data that needs to be read and written to rebuild candidate symmetry motifs and verify them. I don’t think that could be parallelized easily or that it would benefit much from it for reasonably sized SubDs – creating or editing a symmetrical SubD with up to 30k faces seems smooth here.

Definitely not a good candidate for GPU processing, you’d spend more time preparing and sending the SubD data to the GPU than anything else.

I don’t think that would be useful (most of the time the SubD will not be symmetrical and it would be wasted CPU time), but I do think ToNURBS should respect symmetry when it has been previously defined. Adding an option would basically reproduce the Reflect command, so it’s better to leave these two independent, and define the symmetry before calling ToNURBS.

1 Like

This first option is probably a good stopgap solution for me. I have a consistent topology over thousands of meshes, so manually defining one SubD face packing will be tedious but only must be done once.
Symmetrical face packing would be an amazing feature – I appreciate the elevation in priority!

ON_SubDFace::SetPackIdForExperts is where this happens. ON_SubDFace::SetPackRectForExperts is also necessary. When you are done defining the face packing, ON_SubDImpl::SetFacePackingIdAndTopologyHash will freeze it for the SubD.

If you have a single topology, I would highly recommend you script the reconstruction of the symmetry on the NURBS instead. The output order of the NURBS should be stable, and you can use the recent RhinoCommon SDK functions “ProxyBrepSubD” functions to find corresponding faces between the Subd and the NURBS:

1 Like

I will do that! Makes total sense.
Much appreciated!