From cfdf95dc8a0eae6cb18efc4a105b53755a0f0365 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Wed, 18 Feb 2015 16:51:45 +0100 Subject: OBJ importer: add support for (custom) normals. Not much to say, pretty similar to how FBX custom normals import works... --- io_scene_obj/import_obj.py | 66 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 49 insertions(+), 17 deletions(-) (limited to 'io_scene_obj') diff --git a/io_scene_obj/import_obj.py b/io_scene_obj/import_obj.py index cba060c8..18f196e4 100644 --- a/io_scene_obj/import_obj.py +++ b/io_scene_obj/import_obj.py @@ -31,6 +31,7 @@ Note, This loads mesh objects and materials only, nurbs and curves are not suppo http://wiki.blender.org/index.php/Scripts/Manual/Import/wavefront_obj """ +import array import os import time import bpy @@ -379,7 +380,7 @@ def split_mesh(verts_loc, faces, unique_materials, filepath, SPLIT_OB_OR_GROUP): oldkey = -1 # initialize to a value that will never match the key for face in faces: - key = face[4] + key = face[5] if oldkey != key: # Check the key has changed. @@ -407,7 +408,7 @@ def split_mesh(verts_loc, faces, unique_materials, filepath, SPLIT_OB_OR_GROUP): face_vert_loc_indices[enum] = map_index # remap to the local index - matname = face[2] + matname = face[3] if matname and matname not in unique_materials_split: unique_materials_split[matname] = unique_materials[matname] @@ -420,6 +421,7 @@ def split_mesh(verts_loc, faces, unique_materials, filepath, SPLIT_OB_OR_GROUP): def create_mesh(new_objects, use_edges, verts_loc, + verts_nor, verts_tex, faces, unique_materials, @@ -446,6 +448,7 @@ def create_mesh(new_objects, # reverse loop through face indices for f_idx in range(len(faces) - 1, -1, -1): (face_vert_loc_indices, + face_vert_nor_indices, face_vert_tex_indices, context_material, context_smooth_group, @@ -522,6 +525,11 @@ def create_mesh(new_objects, me.polygons.foreach_set("loop_start", faces_loop_start) me.polygons.foreach_set("loop_total", faces_loop_total) + if verts_nor: + # Note: we store 'temp' normals in loops, since validate() may alter final mesh, + # we can only set custom lnors *after* calling it. + me.create_normals_split() + if verts_tex and me.polygons: me.uv_textures.new() @@ -533,6 +541,7 @@ def create_mesh(new_objects, raise Exception("bad face") # Shall not happen, we got rid of those earlier! (face_vert_loc_indices, + face_vert_nor_indices, face_vert_tex_indices, context_material, context_smooth_group, @@ -548,6 +557,10 @@ def create_mesh(new_objects, context_material_old = context_material blen_poly.material_index = mat + if verts_nor: + for face_noidx, lidx in zip(face_vert_nor_indices, blen_poly.loop_indices): + me.loops[lidx].normal[:] = verts_nor[face_noidx] + if verts_tex: if context_material: image = unique_material_images[context_material] @@ -555,8 +568,8 @@ def create_mesh(new_objects, me.uv_textures[0].data[i].image = image blen_uvs = me.uv_layers[0] - for j, lidx in enumerate(blen_poly.loop_indices): - blen_uvs.data[lidx].uv = verts_tex[face_vert_tex_indices[j]] + for face_uvidx, lidx in zip(face_vert_tex_indices, blen_poly.loop_indices): + blen_uvs.data[lidx].uv = verts_tex[face_uvidx] use_edges = use_edges and bool(edges) if use_edges: @@ -564,13 +577,26 @@ def create_mesh(new_objects, # edges should be a list of (a, b) tuples me.edges.foreach_set("vertices", unpack_list(edges)) - me.validate() + me.validate(cleanup_cddata=False) # *Very* important to not remove lnors here! me.update(calc_edges=use_edges) + # XXX If validate changes the geometry, this is likely to be broken... if unique_smooth_groups and sharp_edges: for e in me.edges: if e.key in sharp_edges: e.use_edge_sharp = True + me.show_edge_sharp = True + + if verts_nor: + clnors = array.array('f', [0.0] * (len(me.loops) * 3)) + me.loops.foreach_get("normal", clnors) + + if not unique_smooth_groups: + me.polygons.foreach_set("use_smooth", [True] * len(me.polygons)) + + me.normals_split_custom_set(tuple(zip(*(iter(clnors),) * 3))) + me.use_auto_smooth = True + me.show_edge_sharp = True ob = bpy.data.objects.new(me.name, me) new_objects.append(ob) @@ -717,6 +743,7 @@ def load(operator, context, filepath, time_main = time.time() verts_loc = [] + verts_nor = [] verts_tex = [] faces = [] # tuples of the faces material_libs = [] # filanems to material libs this uses @@ -736,9 +763,6 @@ def load(operator, context, filepath, nurbs = [] context_parm = b'' # used by nurbs too but could be used elsewhere - has_ngons = False - # has_smoothgroups= False - is explicit with len(unique_smooth_groups) being > 0 - # Until we can use sets unique_materials = {} unique_material_images = {} @@ -768,7 +792,7 @@ def load(operator, context, filepath, verts_loc.append((float_func(line_split[1]), float_func(line_split[2]), float_func(line_split[3]))) elif line_start == b'vn': - pass + verts_nor.append((float_func(line_split[1]), float_func(line_split[2]), float_func(line_split[3]))) elif line_start == b'vt': verts_tex.append((float_func(line_split[1]), float_func(line_split[2]))) @@ -784,10 +808,12 @@ def load(operator, context, filepath, else: line_split = line_split[1:] face_vert_loc_indices = [] + face_vert_nor_indices = [] face_vert_tex_indices = [] # Instance a face faces.append((face_vert_loc_indices, + face_vert_nor_indices, face_vert_tex_indices, context_material, context_smooth_group, @@ -813,22 +839,27 @@ def load(operator, context, filepath, face_vert_loc_indices.append(vert_loc_index) + # formatting for faces with normals and textures is + # loc_index/tex_index/nor_index if len(obj_vert) > 1 and obj_vert[1]: - # formatting for faces with normals and textures us - # loc_index/tex_index/nor_index - vert_tex_index = int(obj_vert[1]) - 1 # Make relative negative vert indices absolute if vert_tex_index < 0: vert_tex_index = len(verts_tex) + vert_tex_index + 1 - face_vert_tex_indices.append(vert_tex_index) else: # dummy face_vert_tex_indices.append(0) - if len(face_vert_loc_indices) > 4: - has_ngons = True + if len(obj_vert) > 2 and obj_vert[2]: + vert_nor_index = int(obj_vert[2]) - 1 + # Make relative negative vert indices absolute + if vert_nor_index < 0: + vert_nor_index = len(verts_nor) + vert_nor_index + 1 + face_vert_nor_indices.append(vert_nor_index) + else: + # dummy + face_vert_nor_indices.append(0) 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 @@ -840,10 +871,12 @@ def load(operator, context, filepath, else: line_split = line_split[1:] face_vert_loc_indices = [] + face_vert_nor_indices = [] face_vert_tex_indices = [] # Instance a face faces.append((face_vert_loc_indices, + face_vert_nor_indices, face_vert_tex_indices, context_material, context_smooth_group, @@ -855,8 +888,6 @@ def load(operator, context, filepath, else: context_multi_line = b'' - # isline = line_start == b'l' # UNUSED - for v in line_split: obj_vert = v.split(b'/') vert_loc_index = int(obj_vert[0]) - 1 @@ -986,6 +1017,7 @@ def load(operator, context, filepath, create_mesh(new_objects, use_edges, verts_loc_split, + verts_nor, verts_tex, faces_split, unique_materials_split, -- cgit v1.2.3