cats-blender-plugin icon indicating copy to clipboard operation
cats-blender-plugin copied to clipboard

Separate by loose parts breaks custom normals

Open Mysteryem opened this issue 2 years ago • 0 comments

separate_by_loose_parts In common.py calls bpy.ops.mesh.separate(type='LOOSE') from Object mode. Unfortunately, this has been bugged since Blender 2.80 and tends to breaks custom normals on the mesh (with the exception of flat shaded meshes in 2.90.1 and earlier). For the most part, running the operator in Edit mode works, but only for 2.80 and 2.91.0+. From 2.81.0 to 2.90.1, it's also broken in Edit mode which limits the options for that version.

I've looked at how mmd_tools' custom normals keeper works, but it appears to only work with separating by materials because it groups the custom normals by the material indices of the polygons beforehand, relying on the fact that Blender just so happens to keep the ordering within those groups when separating. To use similar code with separating by loose parts, we would have to figure out each different loose part in the mesh prior to running the operator.

A potential alternative is to duplicate the mesh object before separating and then use the data transfer operator or modifier to copy the custom normals from the duplicate to each of the separated parts, but an approach that doesn't need to create a duplicate mesh would be preferred.

I previously wrote a faster method for finding all edge loops within a mesh that went unused that included code for finding all separate loose parts: https://github.com/Mysteryem/cats-blender-plugin/blob/09da273833b690762f520319f5522b53ebe3bfeb/tools/decimation.py#L632 I/we would have to figure out how to match them up with each separated mesh, assuming it's even possible when separating by loose parts.

The custom normals that break with bpy.ops.mesh.separate(type='SELECTED') appear to be only at the boundaries of the separated parts, so separating by selection should work with each found and selected loose part, since there are no boundaries to begin with due to each loose part being separate from the rest of the mesh already.

I'll probably have a go at changing the code to run the operator in Edit mode for 2.90.1+ and 2.80 and try using bpy.ops.mesh.separate(type='SELECTED') with finding the loose parts manually for 2.81 to 2.90 inclusive. Though what I don't currently know is what does and doesn't work on 2.79.

Details on what works and what doesn't with bpy.ops.mesh.separate in 2.80 and newer: image image

Mysteryem avatar Jun 26 '22 20:06 Mysteryem