1 # SPDX-License-Identifier: GPL-2.0-or-later
4 "name": "Wavefront OBJ format (legacy)",
5 "author": "Campbell Barton, Bastien Montagne",
8 "location": "File > Import-Export",
9 "description": "Import-Export OBJ, Import OBJ mesh, UVs, materials and textures",
11 "doc_url": "{BLENDER_MANUAL_URL}/addons/import_export/scene_obj.html",
12 "support": 'OFFICIAL',
13 "category": "Import-Export",
18 if "import_obj" in locals():
19 importlib
.reload(import_obj
)
20 if "export_obj" in locals():
21 importlib
.reload(export_obj
)
25 from bpy
.props
import (
31 from bpy_extras
.io_utils
import (
40 @orientation_helper(axis_forward
='-Z', axis_up
='Y')
41 class ImportOBJ(bpy
.types
.Operator
, ImportHelper
):
42 """Load a Wavefront OBJ File"""
43 bl_idname
= "import_scene.obj"
44 bl_label
= "Import OBJ"
45 bl_options
= {'PRESET', 'UNDO'}
48 filter_glob
: StringProperty(
49 default
="*.obj;*.mtl",
53 use_edges
: BoolProperty(
55 description
="Import lines and faces with 2 verts as edge",
58 use_smooth_groups
: BoolProperty(
60 description
="Surround smooth groups by sharp edges",
64 use_split_objects
: BoolProperty(
66 description
="Import OBJ Objects into Blender Objects",
69 use_split_groups
: BoolProperty(
71 description
="Import OBJ Groups into Blender Objects",
75 use_groups_as_vgroups
: BoolProperty(
77 description
="Import OBJ groups as vertex groups",
81 use_image_search
: BoolProperty(
83 description
="Search subdirs for any associated images "
84 "(Warning, may be slow)",
88 split_mode
: EnumProperty(
91 ('ON', "Split", "Split geometry, omits vertices unused by edges or faces"),
92 ('OFF', "Keep Vert Order", "Keep vertex order from file"),
96 global_clamp_size
: FloatProperty(
98 description
="Clamp bounds under this value (zero to disable)",
100 soft_min
=0.0, soft_max
=1000.0,
104 def execute(self
, context
):
105 # print("Selected: " + context.active_object.name)
106 from . import import_obj
108 if self
.split_mode
== 'OFF':
109 self
.use_split_objects
= False
110 self
.use_split_groups
= False
112 self
.use_groups_as_vgroups
= False
114 keywords
= self
.as_keywords(
123 global_matrix
= axis_conversion(
124 from_forward
=self
.axis_forward
,
125 from_up
=self
.axis_up
,
127 keywords
["global_matrix"] = global_matrix
129 if bpy
.data
.is_saved
and context
.preferences
.filepaths
.use_relative_paths
:
131 keywords
["relpath"] = os
.path
.dirname(bpy
.data
.filepath
)
133 return import_obj
.load(context
, **keywords
)
135 def draw(self
, context
):
139 class OBJ_PT_import_include(bpy
.types
.Panel
):
140 bl_space_type
= 'FILE_BROWSER'
141 bl_region_type
= 'TOOL_PROPS'
143 bl_parent_id
= "FILE_PT_operator"
146 def poll(cls
, context
):
147 sfile
= context
.space_data
148 operator
= sfile
.active_operator
150 return operator
.bl_idname
== "IMPORT_SCENE_OT_obj"
152 def draw(self
, context
):
154 layout
.use_property_split
= True
155 layout
.use_property_decorate
= False # No animation.
157 sfile
= context
.space_data
158 operator
= sfile
.active_operator
160 layout
.prop(operator
, 'use_image_search')
161 layout
.prop(operator
, 'use_smooth_groups')
162 layout
.prop(operator
, 'use_edges')
165 class OBJ_PT_import_transform(bpy
.types
.Panel
):
166 bl_space_type
= 'FILE_BROWSER'
167 bl_region_type
= 'TOOL_PROPS'
168 bl_label
= "Transform"
169 bl_parent_id
= "FILE_PT_operator"
172 def poll(cls
, context
):
173 sfile
= context
.space_data
174 operator
= sfile
.active_operator
176 return operator
.bl_idname
== "IMPORT_SCENE_OT_obj"
178 def draw(self
, context
):
180 layout
.use_property_split
= True
181 layout
.use_property_decorate
= False # No animation.
183 sfile
= context
.space_data
184 operator
= sfile
.active_operator
186 layout
.prop(operator
, "global_clamp_size")
187 layout
.prop(operator
, "axis_forward")
188 layout
.prop(operator
, "axis_up")
191 class OBJ_PT_import_geometry(bpy
.types
.Panel
):
192 bl_space_type
= 'FILE_BROWSER'
193 bl_region_type
= 'TOOL_PROPS'
194 bl_label
= "Geometry"
195 bl_parent_id
= "FILE_PT_operator"
196 bl_options
= {'DEFAULT_CLOSED'}
199 def poll(cls
, context
):
200 sfile
= context
.space_data
201 operator
= sfile
.active_operator
203 return operator
.bl_idname
== "IMPORT_SCENE_OT_obj"
205 def draw(self
, context
):
208 sfile
= context
.space_data
209 operator
= sfile
.active_operator
211 layout
.row().prop(operator
, "split_mode", expand
=True)
213 layout
.use_property_split
= True
214 layout
.use_property_decorate
= False # No animation.
216 col
= layout
.column()
217 if operator
.split_mode
== 'ON':
218 col
.prop(operator
, "use_split_objects", text
="Split by Object")
219 col
.prop(operator
, "use_split_groups", text
="Split by Group")
221 col
.prop(operator
, "use_groups_as_vgroups")
224 @orientation_helper(axis_forward
='-Z', axis_up
='Y')
225 class ExportOBJ(bpy
.types
.Operator
, ExportHelper
):
226 """Save a Wavefront OBJ File"""
228 bl_idname
= "export_scene.obj"
229 bl_label
= 'Export OBJ'
230 bl_options
= {'PRESET'}
232 filename_ext
= ".obj"
233 filter_glob
: StringProperty(
234 default
="*.obj;*.mtl",
239 use_selection
: BoolProperty(
240 name
="Selection Only",
241 description
="Export selected objects only",
244 use_animation
: BoolProperty(
246 description
="Write out an OBJ for each frame",
251 use_mesh_modifiers
: BoolProperty(
252 name
="Apply Modifiers",
253 description
="Apply modifiers",
257 use_edges
: BoolProperty(
258 name
="Include Edges",
262 use_smooth_groups
: BoolProperty(
263 name
="Smooth Groups",
264 description
="Write sharp edges as smooth groups",
267 use_smooth_groups_bitflags
: BoolProperty(
268 name
="Bitflag Smooth Groups",
269 description
="Same as 'Smooth Groups', but generate smooth groups IDs as bitflags "
270 "(produces at most 32 different smooth groups, usually much less)",
273 use_normals
: BoolProperty(
274 name
="Write Normals",
275 description
="Export one normal per vertex and per face, to represent flat faces and sharp edges",
278 use_uvs
: BoolProperty(
280 description
="Write out the active UV coordinates",
283 use_materials
: BoolProperty(
284 name
="Write Materials",
285 description
="Write out the MTL file",
288 use_triangles
: BoolProperty(
289 name
="Triangulate Faces",
290 description
="Convert all faces to triangles",
293 use_nurbs
: BoolProperty(
295 description
="Write nurbs curves as OBJ nurbs rather than "
296 "converting to geometry",
299 use_vertex_groups
: BoolProperty(
306 use_blen_objects
: BoolProperty(
308 description
="Export Blender objects as OBJ objects",
311 group_by_object
: BoolProperty(
313 description
="Export Blender objects as OBJ groups",
316 group_by_material
: BoolProperty(
317 name
="Material Groups",
318 description
="Generate an OBJ group for each part of a geometry using a different material",
321 keep_vertex_order
: BoolProperty(
322 name
="Keep Vertex Order",
327 global_scale
: FloatProperty(
329 min=0.01, max=1000.0,
333 path_mode
: path_reference_mode
335 check_extension
= True
337 def execute(self
, context
):
338 from . import export_obj
340 from mathutils
import Matrix
341 keywords
= self
.as_keywords(
352 Matrix
.Scale(self
.global_scale
, 4) @
354 to_forward
=self
.axis_forward
,
359 keywords
["global_matrix"] = global_matrix
360 return export_obj
.save(context
, **keywords
)
362 def draw(self
, context
):
366 class OBJ_PT_export_include(bpy
.types
.Panel
):
367 bl_space_type
= 'FILE_BROWSER'
368 bl_region_type
= 'TOOL_PROPS'
370 bl_parent_id
= "FILE_PT_operator"
373 def poll(cls
, context
):
374 sfile
= context
.space_data
375 operator
= sfile
.active_operator
377 return operator
.bl_idname
== "EXPORT_SCENE_OT_obj"
379 def draw(self
, context
):
381 layout
.use_property_split
= True
382 layout
.use_property_decorate
= False # No animation.
384 sfile
= context
.space_data
385 operator
= sfile
.active_operator
387 col
= layout
.column(heading
="Limit to")
388 col
.prop(operator
, 'use_selection')
390 col
= layout
.column(heading
="Objects as", align
=True)
391 col
.prop(operator
, 'use_blen_objects')
392 col
.prop(operator
, 'group_by_object')
393 col
.prop(operator
, 'group_by_material')
397 layout
.prop(operator
, 'use_animation')
400 class OBJ_PT_export_transform(bpy
.types
.Panel
):
401 bl_space_type
= 'FILE_BROWSER'
402 bl_region_type
= 'TOOL_PROPS'
403 bl_label
= "Transform"
404 bl_parent_id
= "FILE_PT_operator"
407 def poll(cls
, context
):
408 sfile
= context
.space_data
409 operator
= sfile
.active_operator
411 return operator
.bl_idname
== "EXPORT_SCENE_OT_obj"
413 def draw(self
, context
):
415 layout
.use_property_split
= True
416 layout
.use_property_decorate
= False # No animation.
418 sfile
= context
.space_data
419 operator
= sfile
.active_operator
421 layout
.prop(operator
, 'global_scale')
422 layout
.prop(operator
, 'path_mode')
423 layout
.prop(operator
, 'axis_forward')
424 layout
.prop(operator
, 'axis_up')
427 class OBJ_PT_export_geometry(bpy
.types
.Panel
):
428 bl_space_type
= 'FILE_BROWSER'
429 bl_region_type
= 'TOOL_PROPS'
430 bl_label
= "Geometry"
431 bl_parent_id
= "FILE_PT_operator"
432 bl_options
= {'DEFAULT_CLOSED'}
435 def poll(cls
, context
):
436 sfile
= context
.space_data
437 operator
= sfile
.active_operator
439 return operator
.bl_idname
== "EXPORT_SCENE_OT_obj"
441 def draw(self
, context
):
443 layout
.use_property_split
= True
444 layout
.use_property_decorate
= False # No animation.
446 sfile
= context
.space_data
447 operator
= sfile
.active_operator
449 layout
.prop(operator
, 'use_mesh_modifiers')
450 layout
.prop(operator
, 'use_smooth_groups')
451 layout
.prop(operator
, 'use_smooth_groups_bitflags')
452 layout
.prop(operator
, 'use_normals')
453 layout
.prop(operator
, 'use_uvs')
454 layout
.prop(operator
, 'use_materials')
455 layout
.prop(operator
, 'use_triangles')
456 layout
.prop(operator
, 'use_nurbs', text
="Curves as NURBS")
457 layout
.prop(operator
, 'use_vertex_groups')
458 layout
.prop(operator
, 'keep_vertex_order')
461 def menu_func_import(self
, context
):
462 self
.layout
.operator(ImportOBJ
.bl_idname
, text
="Wavefront (.obj) (legacy)")
465 def menu_func_export(self
, context
):
466 self
.layout
.operator(ExportOBJ
.bl_idname
, text
="Wavefront (.obj) (legacy)")
471 OBJ_PT_import_include
,
472 OBJ_PT_import_transform
,
473 OBJ_PT_import_geometry
,
475 OBJ_PT_export_include
,
476 OBJ_PT_export_transform
,
477 OBJ_PT_export_geometry
,
483 bpy
.utils
.register_class(cls
)
485 bpy
.types
.TOPBAR_MT_file_import
.append(menu_func_import
)
486 bpy
.types
.TOPBAR_MT_file_export
.append(menu_func_export
)
490 bpy
.types
.TOPBAR_MT_file_import
.remove(menu_func_import
)
491 bpy
.types
.TOPBAR_MT_file_export
.remove(menu_func_export
)
494 bpy
.utils
.unregister_class(cls
)
497 if __name__
== "__main__":