From 4101cb5d5aada3ec81ce6c1ce05f715cc1cf801b Mon Sep 17 00:00:00 2001 From: Bastien Montagne <montagne29@wanadoo.fr> Date: Fri, 21 Sep 2018 20:02:41 +0200 Subject: [PATCH] Initial porting of OBJ (wavefront) IO add-on to 2.8. As with FBX, major changes are no support for exporting materials anymore (since all are nodals), and no more texface at all. --- io_scene_obj/__init__.py | 79 ++++++++++++++++---------------- io_scene_obj/export_obj.py | 14 +++--- io_scene_obj/import_obj.py | 94 ++------------------------------------ 3 files changed, 49 insertions(+), 138 deletions(-) diff --git a/io_scene_obj/__init__.py b/io_scene_obj/__init__.py index 66329447c..c542b2d96 100644 --- a/io_scene_obj/__init__.py +++ b/io_scene_obj/__init__.py @@ -21,8 +21,8 @@ bl_info = { "name": "Wavefront OBJ format", "author": "Campbell Barton, Bastien Montagne", - "version": (2, 3, 6), - "blender": (2, 78, 0), + "version": (3, 3, 6), + "blender": (2, 80, 0), "location": "File > Import-Export", "description": "Import-Export OBJ, Import OBJ mesh, UV's, materials and textures", "warning": "", @@ -48,70 +48,68 @@ from bpy.props import ( from bpy_extras.io_utils import ( ImportHelper, ExportHelper, - orientation_helper_factory, + orientation_helper, path_reference_mode, axis_conversion, ) -IOOBJOrientationHelper = orientation_helper_factory("IOOBJOrientationHelper", axis_forward='-Z', axis_up='Y') - - -class ImportOBJ(bpy.types.Operator, ImportHelper, IOOBJOrientationHelper): +@orientation_helper(axis_forward='-Z', axis_up='Y') +class ImportOBJ(bpy.types.Operator, ImportHelper): """Load a Wavefront OBJ File""" bl_idname = "import_scene.obj" bl_label = "Import OBJ" bl_options = {'PRESET', 'UNDO'} filename_ext = ".obj" - filter_glob = StringProperty( + filter_glob: StringProperty( default="*.obj;*.mtl", options={'HIDDEN'}, ) - use_edges = BoolProperty( + use_edges: BoolProperty( name="Lines", description="Import lines and faces with 2 verts as edge", default=True, ) - use_smooth_groups = BoolProperty( + use_smooth_groups: BoolProperty( name="Smooth Groups", description="Surround smooth groups by sharp edges", default=True, ) - use_split_objects = BoolProperty( + use_split_objects: BoolProperty( name="Object", description="Import OBJ Objects into Blender Objects", default=True, ) - use_split_groups = BoolProperty( + use_split_groups: BoolProperty( name="Group", description="Import OBJ Groups into Blender Objects", default=True, ) - use_groups_as_vgroups = BoolProperty( + use_groups_as_vgroups: BoolProperty( name="Poly Groups", description="Import OBJ groups as vertex groups", default=False, ) - use_image_search = BoolProperty( + use_image_search: BoolProperty( name="Image Search", description="Search subdirs for any associated images " "(Warning, may be slow)", default=True, ) - split_mode = EnumProperty( + split_mode: EnumProperty( name="Split", items=(('ON', "Split", "Split geometry, omits unused verts"), ('OFF', "Keep Vert Order", "Keep vertex order from file"), ), ) - global_clight_size = FloatProperty( + global_clight_size: FloatProperty( name="Clamp Size", description="Clamp bounds under this value (zero to disable)", min=0.0, max=1000.0, @@ -139,7 +137,7 @@ class ImportOBJ(bpy.types.Operator, ImportHelper, IOOBJOrientationHelper): from_up=self.axis_up, ).to_4x4() keywords["global_matrix"] = global_matrix - keywords["use_cycles"] = (context.scene.view_render.engine == 'CYCLES') + keywords["use_cycles"] = True # (context.scene.view_render.engine == 'CYCLES') if bpy.data.is_saved and context.user_preferences.filepaths.use_relative_paths: import os @@ -166,7 +164,7 @@ class ImportOBJ(bpy.types.Operator, ImportHelper, IOOBJOrientationHelper): else: row.prop(self, "use_groups_as_vgroups") - row = layout.split(percentage=0.67) + row = layout.split(factor=0.67) row.prop(self, "global_clight_size") layout.prop(self, "axis_forward") layout.prop(self, "axis_up") @@ -174,7 +172,8 @@ class ImportOBJ(bpy.types.Operator, ImportHelper, IOOBJOrientationHelper): layout.prop(self, "use_image_search") -class ExportOBJ(bpy.types.Operator, ExportHelper, IOOBJOrientationHelper): +@orientation_helper(axis_forward='-Z', axis_up='Y') +class ExportOBJ(bpy.types.Operator, ExportHelper): """Save a Wavefront OBJ File""" bl_idname = "export_scene.obj" @@ -182,113 +181,113 @@ class ExportOBJ(bpy.types.Operator, ExportHelper, IOOBJOrientationHelper): bl_options = {'PRESET'} filename_ext = ".obj" - filter_glob = StringProperty( + filter_glob: StringProperty( default="*.obj;*.mtl", options={'HIDDEN'}, ) # context group - use_selection = BoolProperty( + use_selection: BoolProperty( name="Selection Only", description="Export selected objects only", default=False, ) - use_animation = BoolProperty( + use_animation: BoolProperty( name="Animation", description="Write out an OBJ for each frame", default=False, ) # object group - use_mesh_modifiers = BoolProperty( + use_mesh_modifiers: BoolProperty( name="Apply Modifiers", description="Apply modifiers", default=True, ) - use_mesh_modifiers_render = BoolProperty( + use_mesh_modifiers_render: BoolProperty( name="Use Modifiers Render Settings", description="Use render settings when applying modifiers to mesh objects", default=False, ) # extra data group - use_edges = BoolProperty( + use_edges: BoolProperty( name="Include Edges", description="", default=True, ) - use_smooth_groups = BoolProperty( + use_smooth_groups: BoolProperty( name="Smooth Groups", description="Write sharp edges as smooth groups", default=False, ) - use_smooth_groups_bitflags = BoolProperty( + use_smooth_groups_bitflags: BoolProperty( name="Bitflag Smooth Groups", description="Same as 'Smooth Groups', but generate smooth groups IDs as bitflags " "(produces at most 32 different smooth groups, usually much less)", default=False, ) - use_normals = BoolProperty( + use_normals: BoolProperty( name="Write Normals", description="Export one normal per vertex and per face, to represent flat faces and sharp edges", default=True, ) - use_uvs = BoolProperty( + use_uvs: BoolProperty( name="Include UVs", description="Write out the active UV coordinates", default=True, ) - use_materials = BoolProperty( + use_materials: BoolProperty( name="Write Materials", description="Write out the MTL file", default=True, ) - use_triangles = BoolProperty( + use_triangles: BoolProperty( name="Triangulate Faces", description="Convert all faces to triangles", default=False, ) - use_nurbs = BoolProperty( + use_nurbs: BoolProperty( name="Write Nurbs", description="Write nurbs curves as OBJ nurbs rather than " "converting to geometry", default=False, ) - use_vertex_groups = BoolProperty( + use_vertex_groups: BoolProperty( name="Polygroups", description="", default=False, ) # grouping group - use_blen_objects = BoolProperty( + use_blen_objects: BoolProperty( name="Objects as OBJ Objects", description="", default=True, ) - group_by_object = BoolProperty( + group_by_object: BoolProperty( name="Objects as OBJ Groups ", description="", default=False, ) - group_by_material = BoolProperty( + group_by_material: BoolProperty( name="Material Groups", description="", default=False, ) - keep_vertex_order = BoolProperty( + keep_vertex_order: BoolProperty( name="Keep Vertex Order", description="", default=False, ) - global_scale = FloatProperty( + global_scale: FloatProperty( name="Scale", min=0.01, max=1000.0, default=1.0, ) - path_mode = path_reference_mode + path_mode: path_reference_mode check_extension = True @@ -303,7 +302,7 @@ class ExportOBJ(bpy.types.Operator, ExportHelper, IOOBJOrientationHelper): "filter_glob", )) - global_matrix = (Matrix.Scale(self.global_scale, 4) * + global_matrix = (Matrix.Scale(self.global_scale, 4) @ axis_conversion(to_forward=self.axis_forward, to_up=self.axis_up, ).to_4x4()) diff --git a/io_scene_obj/export_obj.py b/io_scene_obj/export_obj.py index 22d688dab..8184067d0 100644 --- a/io_scene_obj/export_obj.py +++ b/io_scene_obj/export_obj.py @@ -69,7 +69,7 @@ def write_mtl(scene, filepath, path_mode, copy_set, mtl_dict): fw('\nnewmtl %s\n' % mtl_mat_name) # Define a new material: matname_imgname - if mat: + if False and mat: # XXX TODO Support nodal materials. use_mirror = mat.raytrace_mirror.use and mat.raytrace_mirror.reflect_factor != 0.0 # convert from blenders spec to 0 - 1000 range. @@ -139,7 +139,7 @@ def write_mtl(scene, filepath, path_mode, copy_set, mtl_dict): # so we write the materials image. face_img = None - if mat: # No face image. if we havea material search for MTex image. + if False and mat: # XXX TODO support nodal materials. If we have a material search for MTex image. image_map = {} # backwards so topmost are highest priority for mtex in reversed(mat.texture_slots): @@ -230,7 +230,7 @@ def write_nurb(fw, ob, ob_mat): do_endpoints = (do_closed == 0) and nu.use_endpoint_u for pt in nu.points: - fw('v %.6f %.6f %.6f\n' % (ob_mat * pt.co.to_3d())[:]) + fw('v %.6f %.6f %.6f\n' % (ob_mat @ pt.co.to_3d())[:]) pt_num += 1 tot_verts += pt_num @@ -379,7 +379,7 @@ def write_file(filepath, objects, depsgraph, scene, # Nurbs curve support if EXPORT_CURVE_AS_NURBS and test_nurbs_compat(ob): - ob_mat = EXPORT_GLOBAL_MATRIX * ob_mat + ob_mat = EXPORT_GLOBAL_MATRIX @ ob_mat totverts += write_nurb(fw, ob, ob_mat) continue # END NURBS @@ -397,7 +397,7 @@ def write_file(filepath, objects, depsgraph, scene, # _must_ do this first since it re-allocs arrays mesh_triangulate(me) - me.transform(EXPORT_GLOBAL_MATRIX * ob_mat) + me.transform(EXPORT_GLOBAL_MATRIX @ ob_mat) # If negative scaling, we have to invert the normals... if ob_mat.determinant() < 0.0: me.flip_normals() @@ -740,7 +740,7 @@ def _write(context, filepath, if EXPORT_ANIMATION: # Add frame to the filepath. context_name[2] = '_%.6d' % frame - scene.frame_set(frame, 0.0) + scene.frame_set(frame, subframe=0.0) if EXPORT_SEL_ONLY: objects = context.selected_objects else: @@ -773,7 +773,7 @@ def _write(context, filepath, ) progress.leave_substeps() - scene.frame_set(orig_frame, 0.0) + scene.frame_set(orig_frame, subframe=0.0) progress.leave_substeps() diff --git a/io_scene_obj/import_obj.py b/io_scene_obj/import_obj.py index fb2731330..c2998c2ce 100644 --- a/io_scene_obj/import_obj.py +++ b/io_scene_obj/import_obj.py @@ -87,7 +87,7 @@ def obj_image_load(context_imagepath_map, line, DIR, recursive, relpath): def create_materials(filepath, relpath, - material_libs, unique_materials, unique_material_images, + material_libs, unique_materials, use_image_search, use_cycles, float_func): """ Create all the used materials in this obj, @@ -133,48 +133,21 @@ def create_materials(filepath, relpath, mat_wrap.diffuse_image_set(image) mat_wrap.diffuse_mapping_set(coords='UV', translation=map_offset, scale=map_scale) - mtex = blender_material.texture_slots.add() - mtex.texture = texture - mtex.texture_coords = 'UV' - mtex.use_map_color_diffuse = True - - # adds textures to faces (Textured/Alt-Z mode) - # Only apply the diffuse texture to the face if the image has not been set with the inline usemat func. - unique_material_images[context_material_name] = image # set the texface image - elif type == 'Ka': if use_cycles: # XXX Not supported? print("WARNING, currently unsupported ambient texture, skipped.") - mtex = blender_material.texture_slots.add() - mtex.use_map_color_diffuse = False - mtex.texture = texture - mtex.texture_coords = 'UV' - mtex.use_map_ambient = True - elif type == 'Ks': if use_cycles: mat_wrap.specular_image_set(image) mat_wrap.specular_mapping_set(coords='UV', translation=map_offset, scale=map_scale) - mtex = blender_material.texture_slots.add() - mtex.use_map_color_diffuse = False - mtex.texture = texture - mtex.texture_coords = 'UV' - mtex.use_map_color_spec = True - elif type == 'Ke': if use_cycles: # XXX Not supported? print("WARNING, currently unsupported emit texture, skipped.") - mtex = blender_material.texture_slots.add() - mtex.use_map_color_diffuse = False - mtex.texture = texture - mtex.texture_coords = 'UV' - mtex.use_map_emit = True - elif type == 'Bump': bump_mult = map_options.get(b'-bm') bump_mult = float(bump_mult[0]) if (bump_mult is not None and len(bump_mult) > 1) else 1.0 @@ -185,41 +158,16 @@ def create_materials(filepath, relpath, if bump_mult: mat_wrap.normal_factor_set(bump_mult) - mtex = blender_material.texture_slots.add() - mtex.use_map_color_diffuse = False - mtex.texture = texture - mtex.texture_coords = 'UV' - mtex.use_map_normal = True - if bump_mult: - mtex.normal_factor = bump_mult - elif type == 'D': if use_cycles: mat_wrap.alpha_image_set(image) mat_wrap.alpha_mapping_set(coords='UV', translation=map_offset, scale=map_scale) - mtex = blender_material.texture_slots.add() - mtex.use_map_color_diffuse = False - mtex.texture = texture - mtex.texture_coords = 'UV' - mtex.use_map_alpha = True - blender_material.use_transparency = True - blender_material.transparency_method = 'Z_TRANSPARENCY' - if "alpha" not in context_material_vars: - blender_material.alpha = 0.0 - # Todo, unset diffuse material alpha if it has an alpha channel - elif type == 'disp': if use_cycles: mat_wrap.bump_image_set(image) mat_wrap.bump_mapping_set(coords='UV', translation=map_offset, scale=map_scale) - mtex = blender_material.texture_slots.add() - mtex.use_map_color_diffuse = False - mtex.texture = texture - mtex.texture_coords = 'UV' - mtex.use_map_displacement = True - elif type == 'refl': map_type = map_options.get(b'-type') if map_type and map_type != [b'sphere']: @@ -230,12 +178,6 @@ def create_materials(filepath, relpath, mat_wrap.diffuse_image_set(image, projection='SPHERE') mat_wrap.diffuse_mapping_set(coords='Reflection', translation=map_offset, scale=map_scale) - mtex = blender_material.texture_slots.add() - mtex.use_map_color_diffuse = False - mtex.texture = texture - mtex.texture_coords = 'REFLECTION' - mtex.use_map_color_diffuse = True - mtex.mapping = 'SPHERE' else: raise Exception("invalid type %r" % type) @@ -263,18 +205,11 @@ def create_materials(filepath, relpath, for name in unique_materials: # .keys() if name is not None: ma = unique_materials[name] = bpy.data.materials.new(name.decode('utf-8', "replace")) - unique_material_images[name] = None # assign None to all material images to start with, add to later. if use_cycles: from modules import cycles_shader_compat ma_wrap = cycles_shader_compat.CyclesShaderWrapper(ma) cycles_material_wrap_map[ma] = ma_wrap - - # XXX Why was this needed? Cannot find any good reason, and adds stupid empty matslot in case we do not separate - # mesh (see T44947). - #~ unique_materials[None] = None - #~ unique_material_images[None] = None - for libname in sorted(material_libs): # print(libname) mtlpath = os.path.join(DIR, libname) @@ -382,22 +317,15 @@ def create_materials(filepath, relpath, col = (float_func(line_split[1]), float_func(line_split[2]), float_func(line_split[3])) if use_cycles: context_mat_wrap.reflect_color_set(col) - context_material.mirror_color = col - # This is highly approximated, but let's try to stick as close from exporter as possible... :/ - context_material.ambient = sum(context_material.mirror_color) / 3 elif line_id == b'kd': col = (float_func(line_split[1]), float_func(line_split[2]), float_func(line_split[3])) if use_cycles: context_mat_wrap.diffuse_color_set(col) - context_material.diffuse_color = col - context_material.diffuse_intensity = 1.0 elif line_id == b'ks': col = (float_func(line_split[1]), float_func(line_split[2]), float_func(line_split[3])) if use_cycles: context_mat_wrap.specular_color_set(col) context_mat_wrap.hardness_value_set(1.0) - context_material.specular_color = col - context_material.specular_intensity = 1.0 elif line_id == b'ke': # We cannot set context_material.emit right now, we need final diffuse color as well for this. emit_colors[:] = [ @@ -405,23 +333,15 @@ def create_materials(filepath, relpath, elif line_id == b'ns': if use_cycles: context_mat_wrap.hardness_value_set(((float_func(line_split[1]) + 3.0) / 50.0) - 0.65) - context_material.specular_hardness = int((float_func(line_split[1]) * 0.51) + 1) elif line_id == b'ni': # Refraction index (between 1 and 3). if use_cycles: print("WARNING, currently unsupported glass material, skipped.") - context_material.raytrace_transparency.ior = max(1, min(float_func(line_split[1]), 3)) - context_material_vars.add("ior") elif line_id == b'd': # dissolve (transparency) if use_cycles: context_mat_wrap.alpha_value_set(float_func(line_split[1])) - context_material.alpha = float_func(line_split[1]) - context_material.use_transparency = True - context_material.transparency_method = 'Z_TRANSPARENCY' - context_material_vars.add("alpha") elif line_id == b'tr': # translucency if use_cycles: print("WARNING, currently unsupported translucency option, skipped.") - context_material.translucency = float_func(line_split[1]) elif line_id == b'tf': # rgb, filter color, blender has no support for this. pass @@ -601,7 +521,6 @@ def create_mesh(new_objects, verts_tex, faces, unique_materials, - unique_material_images, unique_smooth_groups, vertex_groups, dataname, @@ -756,7 +675,7 @@ def create_mesh(new_objects, me.create_normals_split() if verts_tex and me.polygons: - me.uv_textures.new() + me.uv_layers.new() context_material_old = -1 # avoid a dict lookup mat = 0 # rare case it may be un-initialized. @@ -788,11 +707,6 @@ def create_mesh(new_objects, me.loops[lidx].normal[:] = verts_nor[0 if (face_noidx is ...) else face_noidx] if verts_tex and face_vert_tex_indices: - if context_material: - image = unique_material_images[context_material] - if image: # Can be none if the material dosnt have an image. - me.uv_textures[0].data[i].image = image - blen_uvs = me.uv_layers[0] for face_uvidx, lidx in zip(face_vert_tex_indices, blen_poly.loop_indices): blen_uvs.data[lidx].uv = verts_tex[0 if (face_uvidx is ...) else face_uvidx] @@ -1036,7 +950,6 @@ def load(context, # Until we can use sets unique_materials = {} - unique_material_images = {} unique_smooth_groups = {} # unique_obects= {} - no use for this variable since the objects are stored in the face. @@ -1258,7 +1171,7 @@ def load(context, progress.step("Done, loading materials and images...") create_materials(filepath, relpath, material_libs, unique_materials, - unique_material_images, use_image_search, use_cycles, float_func) + use_image_search, use_cycles, float_func) progress.step("Done, building geometries (verts:%i faces:%i materials: %i smoothgroups:%i) ..." % (len(verts_loc), len(faces), len(unique_materials), len(unique_smooth_groups))) @@ -1284,7 +1197,6 @@ def load(context, verts_tex if use_vtex else [], faces_split, unique_materials_split, - unique_material_images, unique_smooth_groups, vertex_groups, dataname, -- GitLab