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!
This commit is contained in:
parent
884badcfef
commit
88a4883949
|
@ -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:
|
||||
|
|
Loading…
Reference in New Issue