22
$\begingroup$

It is possible to export all object from a scene into different obj files (each object in a obj file separately)?

$\endgroup$
21
$\begingroup$

There doesn't exist a way to do this in the options of the obj importer so what you could do is run a script that loops over the items in your scene, check if it is a mesh and export the current selection to its own file relative to the path your blend file is saved.

import bpy
import os

# get the path where the blend file is located
basedir = bpy.path.abspath('//')

# deselect all objects
bpy.ops.object.select_all(action='DESELECT')    

# loop through all the objects in the scene
scene = bpy.context.scene
for ob in scene.objects:
    # make the current object active and select it
    scene.objects.active = ob
    ob.select = True

    # make sure that we only export meshes
    if ob.type == 'MESH':
        # export the currently selected object to its own file based on its name
        bpy.ops.export_scene.obj(
                filepath=os.path.join(basedir, ob.name + '.obj'),
                use_selection=True,
                )
    # deselect the object and move on to another if any more are left
    ob.select = False

To further tweak your export options, see the parameters that bpy.ops.export_scene_obj() accepts. For example, you can include normals with use_normals=True, change forward axis with axis_forward etc.

There are more stringent checks that could be made but for simple use cases and if used properly, this should suffice.

Also see How to batch import Wavefront OBJ files?.

To have it export only selected objects, comment line 7 and change line 11.

# remove
bpy.ops.object.select_all(action='DESELECT')
# change to this where instead of the entire scene, we only look through selected objects
for ob in bpy.context.selected_objects:

or keep line 11 and add another line

for ob in scene.objects:
    # add the check to see if in selected objects here
    if ob in bpy.context.selected_objects:
        # adjust indentation
        ...
        ...

NB: Make sure the layers you have objects on are selected otherwise you will just get an empty file.

$\endgroup$
  • $\begingroup$ ok, thanks. And how i control options of export with your script (the scale, the axis...)? $\endgroup$ – GabrielS Dec 8 '13 at 22:46
  • $\begingroup$ @GabrielS all the options that you can pass to bpy.ops.export_scene.obj are here, blender.org/documentation/blender_python_api_2_69_release/… $\endgroup$ – iKlsR Dec 8 '13 at 22:47
  • $\begingroup$ @iKlsR, best only link to _release pages, we delete blender_python_api_2_69_4 dirs occasionally. $\endgroup$ – ideasman42 Dec 9 '13 at 5:19
  • $\begingroup$ @iKlsR your script work fine and i have custome it to fit what i want. One more thing. how can i modify the script to export only selected objects? Thanks $\endgroup$ – GabrielS Dec 9 '13 at 11:09
  • $\begingroup$ @GabrielS updated answer. $\endgroup$ – iKlsR Dec 9 '13 at 11:27
12
$\begingroup$

Following Add-on allows to batch export the current selection or simply all scene geometry objects as separate wavefront .obj files. All usual options like Apply Modifiers or Write Materials are available too:

enter image description here Click to enlarge

[Blender 2.8x] io_export_batch_obj.py

# ##### BEGIN GPL LICENSE BLOCK #####
#
#  This program is free software; you can redistribute it and/or
#  modify it under the terms of the GNU General Public License
#  as published by the Free Software Foundation; either version 2
#  of the License, or (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software Foundation,
#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
# <pep8 compliant>

bl_info = {
    "name": "Export multiple OBJ files",
    "author": "p2or, brockmann",
    "version": (0, 2, 0),
    "blender": (2, 80, 0),
    "location": "File > Import-Export",
    "description": "Export multiple OBJ files, UV's, materials",
    "warning": "",
    "wiki_url": "",
    "tracker_url": "",
    "category": "Import-Export"}


import bpy
import os

from bpy_extras.io_utils import ExportHelper

from bpy.props import (BoolProperty,
                       FloatProperty,
                       StringProperty,
                       EnumProperty,
                       CollectionProperty
                       )


class ExportMultipleObjs(bpy.types.Operator, ExportHelper):
    """Batch export objects as obj files"""
    bl_idname = "export_scene.batch_obj"
    bl_label = "Batch export OBJ's"
    bl_options = {'PRESET', 'UNDO'}

    # ExportHelper mixin class uses this
    filename_ext = ".obj"

    filter_glob = StringProperty(
            default="*.obj;*.mtl",
            options={'HIDDEN'},
            )

    # List of operator properties, the attributes will be assigned
    # to the class instance from the operator setting before calling.

    # context group
    use_selection_setting: BoolProperty(
            name="Selection Only",
            description="Export selected objects only",
            default=True,
            )
    use_animation_setting: BoolProperty(
            name="Animation",
            description="Write out an OBJ for each frame",
            default=False,
            )

    # object group
    use_mesh_modifiers_setting: BoolProperty(
            name="Apply Modifiers",
            description="Apply modifiers (preview resolution)",
            default=True,
            )

    # extra data group
    use_edges_setting: BoolProperty(
            name="Include Edges",
            description="",
            default=True,
            )
    use_smooth_groups_setting: BoolProperty(
            name="Smooth Groups",
            description="Write sharp edges as smooth groups",
            default=False,
            )
    use_smooth_groups_bitflags_setting: 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_setting: BoolProperty(
            name="Write Normals",
            description="Export one normal per vertex and per face, to represent flat faces and sharp edges",
            default=False,
            )
    use_uvs_setting: BoolProperty(
            name="Include UVs",
            description="Write out the active UV coordinates",
            default=True,
            )
    use_materials_setting: BoolProperty(
            name="Write Materials",
            description="Write out the MTL file",
            default=True,
            )
    use_triangles_setting: BoolProperty(
            name="Triangulate Faces",
            description="Convert all faces to triangles",
            default=False,
            )
    use_nurbs_setting: BoolProperty(
            name="Write Nurbs",
            description="Write nurbs curves as OBJ nurbs rather than "
                        "converting to geometry",
            default=False,
            )
    use_vertex_groups_setting: BoolProperty(
            name="Polygroups",
            description="",
            default=False,
            )

    use_blen_objects_setting: BoolProperty(
            name="Objects as OBJ Objects",
            description="",
            default=True,
            )
    group_by_object_setting: BoolProperty(
            name="Objects as OBJ Groups ",
            description="",
            default=False,
            )
    group_by_material_setting: BoolProperty(
            name="Material Groups",
            description="",
            default=False,
            )
    keep_vertex_order_setting: BoolProperty(
            name="Keep Vertex Order",
            description="",
            default=False,
            )
    axis_forward_setting: EnumProperty(
            name="Forward",
            items=(('X', "X Forward", ""),
                   ('Y', "Y Forward", ""),
                   ('Z', "Z Forward", ""),
                   ('-X', "-X Forward", ""),
                   ('-Y', "-Y Forward", ""),
                   ('-Z', "-Z Forward", ""),
                   ),
            default='-Z',
            )
    axis_up_setting: EnumProperty(
            name="Up",
            items=(('X', "X Up", ""),
                   ('Y', "Y Up", ""),
                   ('Z', "Z Up", ""),
                   ('-X', "-X Up", ""),
                   ('-Y', "-Y Up", ""),
                   ('-Z', "-Z Up", ""),
                   ),
            default='Y',
            )
    global_scale_setting: FloatProperty(
            name="Scale",
            min=0.01, max=1000.0,
            default=1.0,
            )

    def execute(self, context):                

        # get the folder
        folder_path = os.path.dirname(self.filepath)

        # get objects selected in the viewport
        viewport_selection = context.selected_objects

        # get export objects
        obj_export_list = viewport_selection
        if self.use_selection_setting == False:
            obj_export_list = [i for i in context.scene.objects]

        # deselect all objects
        bpy.ops.object.select_all(action='DESELECT')

        for item in obj_export_list:
            item.select_set(True)
            if item.type == 'MESH':
                file_path = os.path.join(folder_path, "{}.obj".format(item.name))

                bpy.ops.export_scene.obj(
                        filepath=file_path,
                        use_selection=self.use_selection_setting,
                        axis_forward=self.axis_forward_setting, 
                        axis_up=self.axis_up_setting,
                        use_animation=self.use_animation_setting, 
                        use_mesh_modifiers=self.use_mesh_modifiers_setting,
                        use_edges=self.use_edges_setting, 
                        use_smooth_groups=self.use_smooth_groups_setting,
                        use_smooth_groups_bitflags=self.use_smooth_groups_bitflags_setting, 
                        use_normals=self.use_normals_setting,
                        use_uvs=self.use_uvs_setting, 
                        use_materials=self.use_materials_setting,
                        use_triangles=self.use_triangles_setting, 
                        use_nurbs=self.use_nurbs_setting, 
                        use_vertex_groups=self.use_vertex_groups_setting, 
                        use_blen_objects=self.use_blen_objects_setting, 
                        group_by_object=self.group_by_object_setting, 
                        group_by_material=self.group_by_material_setting, 
                        keep_vertex_order=self.keep_vertex_order_setting, 
                        global_scale=self.global_scale_setting
                )
            item.select_set(False)

        # restore viewport selection
        for ob in viewport_selection:
            ob.select_set(True)

        return {'FINISHED'}


# Only needed if you want to add into a dynamic menu
def menu_func_import(self, context):
    self.layout.operator(ExportMultipleObjs.bl_idname, text="Wavefront Batch (.obj)")


def register():
    bpy.utils.register_class(ExportMultipleObjs)
    bpy.types.TOPBAR_MT_file_export.append(menu_func_import)


def unregister():
    bpy.utils.unregister_class(ExportMultipleObjs)
    bpy.types.TOPBAR_MT_file_export.remove(menu_func_import)


if __name__ == "__main__":
    register()

    # test call
    #bpy.ops.export_scene.multiple_objs('INVOKE_DEFAULT')

[Blender 2.7x] io_export_batch_obj.py

# ##### BEGIN GPL LICENSE BLOCK #####
#
#  This program is free software; you can redistribute it and/or
#  modify it under the terms of the GNU General Public License
#  as published by the Free Software Foundation; either version 2
#  of the License, or (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software Foundation,
#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
# <pep8 compliant>

bl_info = {
    "name": "Export multiple OBJ files",
    "author": "poor",
    "version": (0, 1, 0),
    "blender": (2, 74, 0),
    "location": "File > Import-Export",
    "description": "Export multiple OBJ files, UV's, materials",
    "warning": "",
    "wiki_url": "",
    "tracker_url": "",
    "category": "Import-Export"}


import bpy
import os

from bpy_extras.io_utils import ExportHelper

from bpy.props import (BoolProperty,
                       FloatProperty,
                       StringProperty,
                       EnumProperty,
                       CollectionProperty
                       )


def highlightObjects(selection_list):
    for i in selection_list:
        bpy.data.objects[i.name].select = True

class ExportMultipleObjs(bpy.types.Operator, ExportHelper):
    """This appears in the tooltip of the operator and in the generated docs"""
    bl_idname = "export_scene.multiple_objs"
    bl_label = "Export multiple OBJ's"
    bl_options = {'PRESET', 'UNDO'}

    # ExportHelper mixin class uses this
    filename_ext = ".obj"

    filter_glob = StringProperty(
            default="*.obj;*.mtl",
            options={'HIDDEN'},
            )

    # List of operator properties, the attributes will be assigned
    # to the class instance from the operator setting before calling.

    # context group
    use_selection_setting = BoolProperty(
            name="Selection Only",
            description="Export selected objects only",
            default=True,
            )
    use_animation_setting = BoolProperty(
            name="Animation",
            description="Write out an OBJ for each frame",
            default=False,
            )

    # object group
    use_mesh_modifiers_setting = BoolProperty(
            name="Apply Modifiers",
            description="Apply modifiers (preview resolution)",
            default=True,
            )

    # extra data group
    use_edges_setting = BoolProperty(
            name="Include Edges",
            description="",
            default=True,
            )
    use_smooth_groups_setting = BoolProperty(
            name="Smooth Groups",
            description="Write sharp edges as smooth groups",
            default=False,
            )
    use_smooth_groups_bitflags_setting = 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_setting = BoolProperty(
            name="Write Normals",
            description="Export one normal per vertex and per face, to represent flat faces and sharp edges",
            default=False,
            )
    use_uvs_setting = BoolProperty(
            name="Include UVs",
            description="Write out the active UV coordinates",
            default=True,
            )
    use_materials_setting = BoolProperty(
            name="Write Materials",
            description="Write out the MTL file",
            default=True,
            )
    use_triangles_setting = BoolProperty(
            name="Triangulate Faces",
            description="Convert all faces to triangles",
            default=False,
            )
    use_nurbs_setting = BoolProperty(
            name="Write Nurbs",
            description="Write nurbs curves as OBJ nurbs rather than "
                        "converting to geometry",
            default=False,
            )
    use_vertex_groups_setting = BoolProperty(
            name="Polygroups",
            description="",
            default=False,
            )

    # grouping group
    use_blen_objects_setting = BoolProperty(
            name="Objects as OBJ Objects",
            description="",
            default=True,
            )
    group_by_object_setting = BoolProperty(
            name="Objects as OBJ Groups ",
            description="",
            default=False,
            )
    group_by_material_setting = BoolProperty(
            name="Material Groups",
            description="",
            default=False,
            )
    keep_vertex_order_setting = BoolProperty(
            name="Keep Vertex Order",
            description="",
            default=False,
            )

    axis_forward_setting = EnumProperty(
            name="Forward",
            items=(('X', "X Forward", ""),
                   ('Y', "Y Forward", ""),
                   ('Z', "Z Forward", ""),
                   ('-X', "-X Forward", ""),
                   ('-Y', "-Y Forward", ""),
                   ('-Z', "-Z Forward", ""),
                   ),
            default='-Z',
            )
    axis_up_setting = EnumProperty(
            name="Up",
            items=(('X', "X Up", ""),
                   ('Y', "Y Up", ""),
                   ('Z', "Z Up", ""),
                   ('-X', "-X Up", ""),
                   ('-Y', "-Y Up", ""),
                   ('-Z', "-Z Up", ""),
                   ),
            default='Y',
            )
    global_scale_setting = FloatProperty(
            name="Scale",
            min=0.01, max=1000.0,
            default=1.0,
            )

    def execute(self, context):                

        # get the folder
        folder_path = (os.path.dirname(self.filepath))

        # get objects selected in the viewport
        viewport_selection = context.selected_objects

        # get export objects
        obj_export_list = viewport_selection
        if self.use_selection_setting == False:
            obj_export_list = [i for i in context.scene.objects]

        # deselect all objects
        bpy.ops.object.select_all(action='DESELECT')

        for item in obj_export_list:
            item.select = True
            if item.type == 'MESH':
                file_path = os.path.join(folder_path, "{}.obj".format(item.name))
                bpy.ops.export_scene.obj(filepath=file_path, use_selection=True,
                                        axis_forward=self.axis_forward_setting, 
                                        axis_up=self.axis_up_setting,
                                        use_animation=self.use_animation_setting, 
                                        use_mesh_modifiers=self.use_mesh_modifiers_setting,
                                        use_edges=self.use_edges_setting, 
                                        use_smooth_groups=self.use_smooth_groups_setting,
                                        use_smooth_groups_bitflags=self.use_smooth_groups_bitflags_setting, 
                                        use_normals=self.use_normals_setting,
                                        use_uvs=self.use_uvs_setting, 
                                        use_materials=self.use_materials_setting, 
                                        use_triangles=self.use_triangles_setting, 
                                        use_nurbs=self.use_nurbs_setting, 
                                        use_vertex_groups=self.use_vertex_groups_setting, 
                                        use_blen_objects=self.use_blen_objects_setting, 
                                        group_by_object=self.group_by_object_setting, 
                                        group_by_material=self.group_by_material_setting, 
                                        keep_vertex_order=self.keep_vertex_order_setting, 
                                        global_scale=self.global_scale_setting)
            item.select = False

        # restore viewport selection
        highlightObjects(viewport_selection)

        return {'FINISHED'}


# Only needed if you want to add into a dynamic menu
def menu_func_import(self, context):
    self.layout.operator(ExportMultipleObjs.bl_idname, text="Wavefront Batch (.obj)")


def register():
    bpy.utils.register_class(ExportMultipleObjs)
    bpy.types.INFO_MT_file_export.append(menu_func_import)


def unregister():
    bpy.utils.unregister_class(ExportMultipleObjs)
    bpy.types.INFO_MT_file_export.remove(menu_func_import)


if __name__ == "__main__":
    register()

    # test call
    #bpy.ops.export_scene.multiple_objs('INVOKE_DEFAULT')

enter image description here Usual Options

Note: It's just a wrapper of bpy.ops.export_scene.obj operator until exporting multiple files is supported officially.


To import multiple obj files see this answer: https://blender.stackexchange.com/a/31825/3710

$\endgroup$
1
$\begingroup$

For me iKlsR's method did not work when trying to export multiple meshes. I got all meshes in the first exported file. The other exports were rather random, some contained nothing, others contained 3 objects. I have changed some code around and it works for me now.


Method for exporting a selection.

import bpy
import os

# get the current path and make a new folder for the exported meshes
path = bpy.path.abspath('//objs' + os.sep)
os.makedirs(path)

for object in bpy.context.selected_objects:

    # deselect all meshes
    bpy.ops.object.select_all(action='DESELECT')

    # select the object
    object.select = True

    # export object with its name as file name
    bpy.ops.export_scene.obj(
            filepath=path + object.name + '.obj',
            use_selection=True,
            )
$\endgroup$
  • $\begingroup$ thanks for directing me here. I had to modify your version a little more to get it to work on OSX. path = bpy.path.abspath('//') #os.makedirs(path) It was creating a folder but not putting the .obj files into it and it was also prefixing all the names with "objs/" Also, it crashed upon second run unless I deleted the empty folder it's trying to re-create. $\endgroup$ – MarcClintDion Mar 8 '14 at 14:56
  • $\begingroup$ feel free edit my answer, however the code i posted worked for me $\endgroup$ – Vader Mar 8 '14 at 15:21
1
$\begingroup$

Working example for Blender 2.8 to batch export, just change the path

import bpy

#example path to store files
path = 'path\subpath\name'

#store selection
obs = bpy.context.selected_objects

for ob in obs:
    #deselect all but just one object and make it active
    bpy.ops.object.select_all(action='DESELECT')
    ob.select_set(state=True)
    bpy.context.view_layer.objects.active = ob

    #store object location then zero it out
    location = ob.location.copy()
    bpy.ops.object.location_clear()

    #export fbx
    filename = path + ob.name + '.obj'
    bpy.ops.export_scene.obj(filepath=filename, use_selection=True)

    #restore location
    ob.location = location

#reselect originally selected objects  
for ob in obs:
    ob.select_set(state=True)
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.