[Bf-extensions-cvs] [88a4883] master: Fix own error in rBAc307a89e281a2e8 - OBJ importer *do* have to tessellate/untessellate sometimes.

Bastien Montagne noreply at git.blender.org
Thu Feb 19 14:44:28 CET 2015


Commit: 88a48839490e56a4856be78380cbd40bbdcd2d04
Author: Bastien Montagne
Date:   Thu Feb 19 13:01:51 2015 +0100
Branches: master
https://developer.blender.org/rBA88a48839490e56a4856be78380cbd40bbdcd2d04

Fix own error in rBAc307a89e281a2e8 - OBJ importer *do* have to tessellate/untessellate sometimes.

Issue comes with ngons having holes (i.e. ngons using the same edge more than once).
This is not supported in Blender, so we have to 'work around' it.

However, we can limit this behavior to ngons actually 'blender-invalid', no need to
do that systematically.

So this commit still allows for much better performances with 'usual' ngons.
Those with holes get back to previous performances, more or less.

Many thanks to Campbell for the headup!

===================================================================

M	io_scene_obj/import_obj.py

===================================================================

diff --git a/io_scene_obj/import_obj.py b/io_scene_obj/import_obj.py
index 10c0ae1..ba2cf54 100644
--- a/io_scene_obj/import_obj.py
+++ b/io_scene_obj/import_obj.py
@@ -432,6 +432,7 @@ def create_mesh(new_objects,
         smooth_group_users = {context_smooth_group: {} for context_smooth_group in unique_smooth_groups.keys()}
         context_smooth_group_old = -1
 
+    fgon_edges = set()  # Used for storing fgon keys whe we need to tesselate/untesselate them (ngons with hole).
     edges = []
     tot_loops = 0
 
@@ -445,6 +446,7 @@ def create_mesh(new_objects,
          context_material,
          context_smooth_group,
          context_object,
+         face_invalid_blenpoly,
          ) = faces[f_idx]
 
         len_face_vert_loc_indices = len(face_vert_loc_indices)
@@ -459,7 +461,6 @@ def create_mesh(new_objects,
             faces.pop(f_idx)
 
         else:
-            tot_loops += len_face_vert_loc_indices
             # Smooth Group
             if unique_smooth_groups and context_smooth_group:
                 # Is a part of of a smooth group and is a face
@@ -467,12 +468,54 @@ def create_mesh(new_objects,
                     edge_dict = smooth_group_users[context_smooth_group]
                     context_smooth_group_old = context_smooth_group
 
-                for i in range(len_face_vert_loc_indices):
-                    i1 = face_vert_loc_indices[i]
-                    i2 = face_vert_loc_indices[i - 1]
-                    edge_key = (i1, i2) if i1 < i2 else (i2, i1)
+                prev_vidx = face_vert_loc_indices[-1]
+                for vidx in face_vert_loc_indices:
+                    edge_key = (prev_vidx, vidx) if (prev_vidx < vidx) else (vidx, prev_vidx)
+                    prev_vidx = vidx
                     edge_dict[edge_key] = edge_dict.get(edge_key, 0) + 1
 
+            # NGons into triangles
+            if face_invalid_blenpoly:
+                from bpy_extras.mesh_utils import ngon_tessellate
+                ngon_face_indices = ngon_tessellate(verts_loc, face_vert_loc_indices)
+                faces.extend([([face_vert_loc_indices[ngon[0]],
+                                face_vert_loc_indices[ngon[1]],
+                                face_vert_loc_indices[ngon[2]],
+                                ],
+                               [face_vert_nor_indices[ngon[0]],
+                                face_vert_nor_indices[ngon[1]],
+                                face_vert_nor_indices[ngon[2]],
+                                ],
+                               [face_vert_tex_indices[ngon[0]],
+                                face_vert_tex_indices[ngon[1]],
+                                face_vert_tex_indices[ngon[2]],
+                                ],
+                               context_material,
+                               context_smooth_group,
+                               context_object,
+                               [],
+                              )
+                             for ngon in ngon_face_indices]
+                            )
+                tot_loops += 3 * len(ngon_face_indices)
+
+                # edges to make ngons
+                edge_users = set()
+                for ngon in ngon_face_indices:
+                    prev_vidx = face_vert_loc_indices[ngon[-1]]
+                    for ngidx in ngon:
+                        vidx = face_vert_loc_indices[ngidx]
+                        edge_key = (prev_vidx, vidx) if (prev_vidx < vidx) else (vidx, prev_vidx)
+                        prev_vidx = vidx
+                        if edge_key in edge_users:
+                            fgon_edges.add(edge_key)
+                        else:
+                            edge_users.add(edge_key)
+
+                faces.pop(f_idx)
+            else:
+                tot_loops += len_face_vert_loc_indices
+
     # Build sharp edges
     if unique_smooth_groups:
         for edge_dict in smooth_group_users.values():
@@ -538,6 +581,7 @@ def create_mesh(new_objects,
          context_material,
          context_smooth_group,
          context_object,
+         face_invalid_blenpoly,
          ) = face
 
         if context_smooth_group:
@@ -572,6 +616,24 @@ def create_mesh(new_objects,
     me.validate(cleanup_cddata=False)  # *Very* important to not remove lnors here!
     me.update(calc_edges=use_edges)
 
+    # Un-tessellate as much as possible, in case we had to triangulate some ngons...
+    if fgon_edges:
+        import bmesh
+        bm = bmesh.new()
+        bm.from_mesh(me)
+        verts = bm.verts[:]
+        get = bm.edges.get
+        edges = [get((verts[vidx1], verts[vidx2])) for vidx1, vidx2 in fgon_edges]
+        try:
+            bmesh.ops.dissolve_edges(bm, edges=edges, use_verts=False)
+        except:
+            # Possible dissolve fails for some edges, but don't fail silently in case this is a real bug.
+            import traceback
+            traceback.print_exc()
+
+        bm.to_mesh(me)
+        bm.free()
+
     # XXX If validate changes the geometry, this is likely to be broken...
     if unique_smooth_groups and sharp_edges:
         for e in me.edges:
@@ -739,6 +801,7 @@ def load(operator, context, filepath,
             context_material,
             context_smooth_group,
             context_object,
+            [],  # If non-empty, that face is a Blender-invalid ngon (holes...), need a mutable object for that...
         )
 
     print('\nimporting obj %r' % filepath)
@@ -790,6 +853,9 @@ def load(operator, context, filepath,
     face_vert_loc_indices = None
     face_vert_nor_indices = None
     face_vert_tex_indices = None
+    face_items_usage = set()
+    face_invalid_blenpoly = None
+    prev_vidx = None
     face = None
 
     print("\tparsing obj file...")
@@ -820,8 +886,9 @@ def load(operator, context, filepath,
                 line_split = line_split[1:]
                 # Instance a face
                 face = create_face(context_material, context_smooth_group, context_object)
-                face_vert_loc_indices, face_vert_nor_indices, face_vert_tex_indices, _1, _2, _3 = face
+                face_vert_loc_indices, face_vert_nor_indices, face_vert_tex_indices, _1, _2, _3, face_invalid_blenpoly = face
                 faces.append(face)
+                face_items_usage.clear()
             # Else, use face_vert_loc_indices and face_vert_tex_indices previously defined and used the obj_face
 
             context_multi_line = b'f' if strip_slash(line_split) else b''
@@ -833,6 +900,14 @@ def load(operator, context, filepath,
                 # *warning*, this wont work for files that have groups defined around verts
                 if use_groups_as_vgroups and context_vgroup:
                     vertex_groups[context_vgroup].append(vert_loc_index)
+                # This a first round to quick-detect ngons that *may* use a same edge more than once.
+                # Potential candidate will be re-checked once we have done parsing the whole face.
+                if not face_invalid_blenpoly:
+                    # If we use more than once a same vertex, invalid ngon is suspected.
+                    if vert_loc_index in face_items_usage:
+                        face_invalid_blenpoly.append(True)
+                    else:
+                        face_items_usage.add(vert_loc_index)
                 face_vert_loc_indices.append(vert_loc_index)
 
                 # formatting for faces with normals and textures is
@@ -849,6 +924,20 @@ def load(operator, context, filepath,
                     # dummy
                     face_vert_nor_indices.append(0)
 
+            if not context_multi_line:
+                # Means we have finished a face, we have to do final check if ngon is suspected to be blender-invalid...
+                if face_invalid_blenpoly:
+                    face_invalid_blenpoly.clear()
+                    face_items_usage.clear()
+                    prev_vidx = face_vert_loc_indices[-1]
+                    for vidx in face_vert_loc_indices:
+                        edge_key = (prev_vidx, vidx) if (prev_vidx < vidx) else (vidx, prev_vidx)
+                        if edge_key in face_items_usage:
+                            face_invalid_blenpoly.append(True)
+                            break
+                        face_items_usage.add(edge_key)
+                        prev_vidx = vidx
+
         elif use_edges and (line_start == b'l' or context_multi_line == b'l'):
             # very similar to the face load function above with some parts removed
             if not context_multi_line:



More information about the Bf-extensions-cvs mailing list