I am processing OBJ files generated by another program. This involves tidying the mesh, marking the seam and unwrapping. It runs in background mode.
The input OBJ files often have very long thin faces in areas of tight curvature that cause issues with unwrapping. I have a solution that picks vertices either side of an area of long thin faces and uses bpy.ops.mesh.vert_connect_path
to cut the faces. This works, and produces a minimally distorted UV. It's rather clumsy though, and generates so many Assert stack traces that I had to pipe stderr
to /dev/null
, but it does work!
So I am looking for alternative solutions. The basic intention is to identify all long narrow faces and then split them into smaller faces that are a bit closer to squares/equilateral triangles. bpy.ops.mesh.subdivide
, and other functions such as triangle fill and poke are not useful because they split the face into more faces that are just as narrow. Looking at the bmesh functions, I came across bmesh.ops.bisect_edges
, bmesh.ops.connect_verts
, bmesh.ops.triangulate
, bmesh.ops.subdivide_edge
and bmesh.ops.triangle_fill
, but the documentation is a bit sparse.
What would be the most efficient method? I can identify the problematic faces quite easily, but I'm not sure of the best way to split them.
Here's what I'm currently using. I have a list of tuples of BMVerts It was easier to identify them using bmesh, but the vert_connect_path operator
uses MeshVertex, so I'm making the rather dodgy assumption that the indexes are the same:
(looping around the X=0.05cm ring while in bmesh and pairing up vertices)
vertPairs05.append((topLeft05XVert, bottomLeft05XVert))
vertPairs05.append((topRight05XVert, bottomRight05XVert))
...
# more processing (which doesn't delete anything but does add faces to fill the other end), then save:
...
bm.to_mesh(me)
bpy.ops.object.select_all(action='DESELECT')
scn = bpy.context.scene
scn.objects.active = bpy.data.objects[0]
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.select_all(action='SELECT')
bpy.ops.mesh.customdata_custom_splitnormals_clear()
bpy.ops.mesh.normals_make_consistent(inside=False)
for pair in vertPairs05:
bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.object.mode_set(mode='OBJECT')
me.vertices[pair[0].index].select = True
me.vertices[pair[1].index].select = True
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.vert_connect_path()
This works, but takes about a half to one second for each path, and generates a number of Assert errors and stack traces, all apparently identical:
blender(BLI_system_backtrace+0x33) [0x560a2b4dfe93]
blender(BM_face_splits_check_legal+0x56f) [0x560a2b02dd8f]
blender(+0x163c365) [0x560a2b065365]
blender(bmo_connect_verts_exec+0x5ba) [0x560a2b0659aa]
blender(BMO_op_exec+0x31) [0x560a2b026901]
blender(bmo_connect_vert_pair_exec+0x1091) [0x560a2b0689f1]
...
BLI_assert failed: /build/blender-Nh0fvZ/blender-2.79.b+dfsg0/source/blender/bmesh/intern/bmesh_polygon.c:1164, BM_face_splits_check_legal(), at 'BM_face_is_normal_valid(f)'
Using Blender 2.79, the Ubuntu package for 18.04.4 LTS. No reason why I couldn't install a more recent version of course.
I'm using Bmesh for analyzing the mesh because it's a lot easier to navigate around with it. I'll do some more research on those functions I came across above, but my reason for posting was because splitting a face seems like an operation that others would hopefully have encountered before.
UPDATE 2:
Here's a Blend file showing the long narrow faces that have been produced, and the resulting distortion in the UV.
Showing how my first attempts at cutting the faces have resulted in much less distortion.