It is possible to export all object from a scene into different obj files (each object in a obj file separately)?
6 Answers
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.
Blender 3.1+
As of Blender 3.1.0 the name of the operator has been changed to obj_export()
and is now part of the WindowManager
namespace bpy.ops.wm.obj_export(filepath="//")
:
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:
# Select each object
ob.select_set(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.wm.obj_export(
filepath=os.path.join(basedir, ob.name + '.obj'),
export_selected_objects=True,
)
# Deselect the object and move on to another if any more are left
ob.select_set(False)
Blender 2.8+
As of Blender 2.8.0 the selection attribute (Object.select
) has been removed in favor of get/set functions Object.select_set(State)
and Object.select_get()
to set and get the current selection state of each object:
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:
# Select each object
ob.select_set(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_set(False)
Blender 2.7x
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.
-
$\begingroup$ ok, thanks. And how i control options of export with your script (the scale, the axis...)? $\endgroup$– GabrielSCommented Dec 8, 2013 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$– iKlsRCommented Dec 8, 2013 at 22:47 -
$\begingroup$ @iKlsR, best only link to
_release
pages, we deleteblender_python_api_2_69_4
dirs occasionally. $\endgroup$ Commented Dec 9, 2013 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$– GabrielSCommented Dec 9, 2013 at 11:09
-
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 in the Properties Panel N too.
Repository: github.com/p2or/blender-batch-export-wavefront-obj
io_batch_export_objs.py
(updated for 3.6+)
# ##### 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": "OBJ Batch Export",
"author": "p2or, brockmann, trippeljojo",
"version": (0, 5, 0),
"blender": (3, 6, 0),
"location": "File > Import-Export",
"description": "Export multiple OBJ files, their UVs and 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,
IntProperty,
FloatProperty,
StringProperty,
EnumProperty,
CollectionProperty
)
class WM_OT_batchExportObjs(bpy.types.Operator, ExportHelper):
"""Batch export the scene to separate 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'},)
selection_only: BoolProperty(
name="Selection Only",
description="Export selected objects only",
default=True,)
scale_factor: FloatProperty(
name="Scale",
min=0.01, max=1000.0,
default=1.0,)
axis_forward: EnumProperty(
name="Forward Axis",
items=(('X', "X", "Positive X Axis"),
('Y', "Y", "Positive Y Axis"),
('Z', "Z", "Positive Z Axis"),
('NEGATIVE_X', "-X", "Negative X Axis"),
('NEGATIVE_Y', "-Y", "Negative Y Axis"),
('NEGATIVE_Z', "-Z (Default)", "Negative Z Axis"),),
default='NEGATIVE_Z')
axis_up: EnumProperty(
name="Up Axis",
items=(('X', "X Up", "Positive X Axis"),
('Y', "Y Up (Default)", "Positive Y Axis"),
('Z', "Z Up", "Positive Z Axis"),
('NEGATIVE_X', "-X Up", "Negative X Axis"),
('NEGATIVE_Y', "-Y Up", "Negative Y Axis"),
('NEGATIVE_Z', "-Z Up", "Negative Z Axis"),),
default='Y')
modifiers_apply: BoolProperty(
name="Apply Modifiers",
description="Apply modifiers to exported meshes",
default=False)
eval_mode: EnumProperty(
name="Properties",
description="Determines properties like object visibility, "
"modifiers etc., where they differ for Render and Viewport",
items=(('DAG_EVAL_VIEWPORT',
"Viewport (Default)",
"Export objects as they appear in the viewport"),
('DAG_EVAL_RENDER',
"Render",
"Export objects as they appear in render"),),
default='DAG_EVAL_VIEWPORT')
# GEOMETRY
write_uvs: BoolProperty(
name="UV Coordinates",
description="Export the UV coordinates",
default=True)
write_normals: BoolProperty(
name="Normals",
description="Export per-face normals if the face is flat-shaded, "
"per-face-per-loop normals if smooth-shaded",
default=True)
write_colors: BoolProperty(
name="Colors",
description="Export per-vertex colors",
default=False)
triangulate_faces: BoolProperty(
name="Triangulated Mesh",
description='All ngons with four or more vertices will be triangulated. '
'Meshes in the scene will not be affected. Behaves like '
'Triangulate Modifier with ngon-method: "Beauty", quad-method: '
'"Shortest Diagonal", min vertices: 4.',
default=False)
write_nurbs: BoolProperty(
name="Curves as NURBS",
description="Export curves in parametric form instead of exporting as mesh",
default=False)
# MATERIALS
write_materials: BoolProperty(
name="Export Materials",
description="Export MTL library. There must be a Principled-BSDF "
"node for image textures to be exported to the MTL file.",
default=True)
write_pbr: BoolProperty(
name="PBR Extensions",
description="Export MTL library using PBR extensions (roughness, metallic, "
"sheen, coat, anisotropy, transmission)",
default=False)
path_mode: EnumProperty(
name="Path Mode",
description="Method used to reference paths",
items=(('AUTO', "Auto", "Use relative paths with subdirectories only"),
('ABSOLUTE', "Absolute", "Always write absolute paths"),
('RELATIVE', "Relative", "Write relative paths where possible"),
('MATCH', "Match", "OMatch absolute/relative setting with input path"),
('STRIP', "Strip", "Write filename only"),
('COPY', "Copy", "Copy the file to the destination path"),
),
default='AUTO')
# GROUPING
group_by_object: BoolProperty(
name="Object Groups",
description="Append mesh name to object name, separated by a '_'",
default=False)
group_by_material: BoolProperty(
name="Material Groups",
description="Generate an OBK group for each part of a geometry "
"using a different material",
default=False)
group_by_vertex: BoolProperty(
name="Vertex Groups",
description="Export the name of the vertex group of a face. "
"It is approximated by choosing the vertex group "
"with the most members amoung the vertices of a face",
default=False)
smoothing_groups: BoolProperty(
name="Smooth Groups",
description='Every smooth-shaded face is assigned group "1" and '
'every flat-shaded face "off".',
default=False)
smoothing_group_bitflags: BoolProperty(
name="Smooth Group Bitflags",
description="Same as 'Smooth Groups', but generate smooth groups IDs as bitflags "
"(produces at most 32 different smooth groups, usually much less)",
default=False)
def execute(self, context):
# Get the current folder
folder_path = os.path.dirname(self.filepath)
# Get all objects selected in the viewport
viewport_selection = candidates = context.selected_objects
if self.selection_only == False:
candidates = [o for o in context.scene.objects]
# Deselect all objects
bpy.ops.object.select_all(action='DESELECT')
for obj in [o for o in candidates if o.type == 'MESH']:
obj.select_set(True)
file_path = os.path.join(folder_path, "{}.obj".format(obj.name))
bpy.ops.wm.obj_export(
filepath=file_path,
export_animation=False,
#start_frame=-2147483648,
# end_frame=2147483647,
forward_axis=self.axis_forward,
up_axis=self.axis_up,
global_scale=self.scale_factor,
apply_modifiers=self.modifiers_apply,
export_eval_mode=self.eval_mode,
export_selected_objects=True,
export_uv=self.write_uvs,
export_normals=self.write_normals,
export_colors=self.write_colors,
export_materials=self.write_materials,
export_pbr_extensions=self.write_pbr,
path_mode=self.path_mode,
export_triangulated_mesh=self.triangulate_faces,
export_curves_as_nurbs=self.write_nurbs,
export_object_groups=self.group_by_object,
export_material_groups=self.group_by_material,
export_vertex_groups=self.group_by_vertex,
export_smooth_groups=self.smoothing_groups,
smooth_group_bitflags=self.smoothing_group_bitflags
)
obj.select_set(False)
# Restore Viewport Selection
for obj in viewport_selection:
obj.select_set(True)
return {'FINISHED'}
def menu_func_import(self, context):
self.layout.operator(WM_OT_batchExportObjs.bl_idname, text="Wavefront Batch (.obj)")
def register():
bpy.utils.register_class(WM_OT_batchExportObjs)
#bpy.types.TOPBAR_MT_file_export.append(menu_func_import)
def unregister():
bpy.utils.unregister_class(WM_OT_batchExportObjs)
#bpy.types.TOPBAR_MT_file_export.remove(menu_func_import)
if __name__ == "__main__":
register()
# test call
#bpy.ops.export_scene.batch_obj('INVOKE_DEFAULT')
Note: The add-on is just a wrapper of wm.obj_export()
or export_scene.obj()
operator in versions prior to Blender 3.2.0
until exporting multiple files is officially supported. To import multiple obj files see this answer: How to batch import Wavefront OBJ files?
Versions
To keep track of all the changes over the years I decided to create a dedicated repository instead of posting each version here, which makes it easier to download as well:
-
$\begingroup$ Is there a way to export the object with the center of object for the mesh instead of the global origin? $\endgroup$ Commented Jan 21, 2020 at 4:15
-
$\begingroup$ I figured it out, I added a
use_mesh_as_center
option that sets the mesh's location to (0, 0, 0) before exporting and resets it back to its original after $\endgroup$ Commented Jan 21, 2020 at 5:28 -
$\begingroup$ Hi @p2or, thanks for the great answer. Do you know if there is a way to save modifiers along with the .obj, so that importing them later will preserve them? (I have a relevant question here: blender.stackexchange.com/questions/181143/…) $\endgroup$ Commented Jun 5, 2020 at 14:17
-
1$\begingroup$ .obj is a pretty old file format and doesn't allow to preserve any modifiers. Even when using alembic or usd, there is no way to preserve that (in 2020). If there is a serious reason to do that, I'd suggest to save all the modifier properties in a json string as text file and check for that file when loading the data back in. Cheers @ComputerScientist $\endgroup$– p2orCommented Jun 6, 2020 at 12:58
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)
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,
)
-
$\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$ Commented Mar 8, 2014 at 14:56
-
$\begingroup$ feel free edit my answer, however the code i posted worked for me $\endgroup$– VaderCommented Mar 8, 2014 at 15:21
For Blender 2.92.1
multiobj_exporter.py
import bpy
import os
basedir = 'absolute path'
sel_objs = [obj for obj in bpy.context.scene.objects if obj.type == 'MESH']
bpy.ops.object.select_all(action='DESELECT')
for obj in sel_objs:
bpy.context.view_layer.objects.active = obj
obj.select_set(True)
bpy.ops.export_scene.obj(
filepath=os.path.join(basedir, obj.name + '.obj'),
use_selection=True,
)
obj.select_set(False)
the code worked with only background option like below because an context error occurred. If anyone know the reason why, please tell me.
$ blender --background --python multiobj_exporter.py